### Install and Run Readwise MCP Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Commands for installing the package globally and starting the server with an API key. ```bash # Global installation npm install -g readwise-mcp # Start the server with API key readwise-mcp --api-key YOUR_READWISE_API_KEY ``` -------------------------------- ### Build Readwise MCP from source Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Clone the repository, install dependencies, and build the project from source. ```bash git clone https://github.com/IAmAlexander/readwise-mcp.git cd readwise-mcp npm install npm run build ``` -------------------------------- ### Run MCP Inspector Source: https://github.com/iamalexander/readwise-mcp/blob/main/docs/testing-and-debugging.md Starts the Readwise MCP server with SSE transport and launches the MCP Inspector for interactive testing. Ensure Node.js and npm/yarn are installed. ```bash npm run run-inspector ``` -------------------------------- ### Install Readwise MCP via Smithery CLI Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Install the Readwise MCP client using the Smithery CLI for use with Claude. ```bash npx @smithery/cli install @iamalexander/readwise-mcp --client claude ``` -------------------------------- ### Run HTTP/SSE Server Source: https://github.com/iamalexander/readwise-mcp/blob/main/ARCHITECTURE.md Commands to start the server in SSE mode with optional debug logging. ```bash # Start SSE server readwise-mcp --transport sse --port 3001 # With debug logging readwise-mcp --transport sse --port 3001 --debug ``` -------------------------------- ### Install Readwise MCP via npm Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Install the Readwise MCP server globally using npm after obtaining a Readwise API token. ```bash npm install -g readwise-mcp ``` -------------------------------- ### Install Readwise MCP via Smithery CLI Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Use the Smithery CLI to automatically install the Readwise MCP for Claude. ```bash npx -y @smithery/cli install @iamalexander/readwise-mcp --client claude ``` -------------------------------- ### Initialize Web Client Source: https://github.com/iamalexander/readwise-mcp/blob/main/examples/web-client.html Logs initialization status and provides instructions for starting the MCP server upon DOM content load. ```javascript // Initialize document.addEventListener('DOMContentLoaded', function() { logEvent('Web client initialized', 'info'); logEvent('To use this client, start the Readwise MCP server with SSE transport:', 'info'); logEvent('npm run public', 'info'); }); ``` -------------------------------- ### Vercel Deployment Commands Source: https://github.com/iamalexander/readwise-mcp/blob/main/docs/serverless-deployment.md Commands for installing the Vercel CLI, authenticating, building, and deploying the project. ```bash npm install -g vercel ``` ```bash vercel login ``` ```bash npm run build ``` ```bash npm run deploy ``` ```bash npm run deploy:prod ``` ```bash vercel env add READWISE_API_KEY ``` -------------------------------- ### Configure Readwise MCP API Key Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Set up the Readwise MCP server by running the setup wizard or providing the API key directly as a command-line argument. ```bash # Run the setup wizard npm run setup # Or start with the API key directly readwise-mcp --api-key YOUR_API_KEY ``` -------------------------------- ### Setup YouTube Player Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/video-features.html Initializes the YouTube player by extracting the video ID from a URL and loading the YouTube IFrame Player API if necessary. Handles both `youtube.com` and `youtu.be` URL formats. ```javascript function setupYouTubePlayer(url) { // Extract video ID from URL let videoId; if (url.includes('youtube.com')) { const urlParams = new URLSearchParams(new URL(url).search); videoId = urlParams.get('v'); } else if (url.includes('youtu.be')) { videoId = url.split('/').pop(); } if (!videoId) { videoPlayerContainer.classList.add('hidden'); return; } videoPlayerContainer.classList.remove('hidden'); // Load YouTube API if not already loaded if (!window.YT) { const tag = document.createElement('script'); tag.src = 'https://www.youtube.com/iframe_api'; const firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); window.onYouTubeIframeAPIReady = () => { createYouTubePlayer(videoId); }; } else { createYouTubePlayer(videoId); } } ``` -------------------------------- ### Example API Authentication Error Response Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Shows an example of an API authentication error, indicating a missing Readwise API key. ```json { error: { type: 'validation', details: { code: 'authentication_required', message: 'Readwise API key is required. Please provide your API key from https://readwise.io/access_token' } }, request_id: 'req-002' } ``` -------------------------------- ### Run Simple MCP Server for Testing Source: https://github.com/iamalexander/readwise-mcp/blob/main/test-scripts/README.md Helper script to start the MCP server in a specific transport mode (stdio or SSE), with built-in port management and cleanup. ```bash ./run-simple-server.sh ``` -------------------------------- ### Retrieve Highlights via get_highlights Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Example tool call and response for fetching highlights from the Readwise library. ```typescript // MCP Tool Call const request = { type: 'tool_call', name: 'get_highlights', request_id: 'req-001', parameters: { book_id: '12345', // Optional: filter by book page: 1, // Optional: page number (default: 1) page_size: 50, // Optional: results per page (1-100) search: 'machine learning' // Optional: search term } }; // Expected Response { result: { count: 150, next: 'https://readwise.io/api/v2/highlights?page=2', previous: null, results: [ { id: 'hl_123', text: 'The key to machine learning is understanding the data...', note: 'Important concept for ML fundamentals', location: 42, book_id: '12345', book_title: 'Machine Learning Basics', book_author: 'John Doe', tags: ['ml', 'fundamentals'], created_at: '2024-01-15T10:30:00Z', updated_at: '2024-01-15T10:30:00Z' } ] }, request_id: 'req-001' } ``` -------------------------------- ### Test Smithery configuration locally Source: https://github.com/iamalexander/readwise-mcp/blob/main/SMITHERY.md Use the Smithery CLI to verify the server configuration before deployment. Requires the Smithery CLI to be installed globally. ```bash # Install Smithery CLI if not already installed npm install -g @smithery/cli # Run the server with test configuration npx @smithery/cli run server-readwise-mcp --config '{"readwiseApiToken":"your-token-here"}' ``` -------------------------------- ### Retrieve Books via get_books Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Example tool call and response for fetching book metadata from the Readwise library. ```typescript // MCP Tool Call const request = { type: 'tool_call', name: 'get_books', request_id: 'req-002', parameters: { category: 'books', // Optional: 'books', 'articles', 'tweets', 'podcasts' page: 1, page_size: 25 } }; // Expected Response { result: { count: 100, next: 'https://readwise.io/api/v2/books?page=2', previous: null, results: [ { id: '12345', title: 'Atomic Habits', author: 'James Clear', category: 'books', source: 'kindle', cover_image_url: 'https://covers.readwise.io/atomic-habits.jpg', highlights_count: 45, source_url: 'https://amazon.com/dp/B07D23CFGR' } ] }, request_id: 'req-002' } ``` -------------------------------- ### Add Readwise MCP via Claude CLI Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Install the Readwise MCP client using the Claude CLI with an HTTP transport. ```bash claude mcp add readwise-mcp --transport http https://server.smithery.ai/@IAmAlexander/readwise-mcp/mcp ``` -------------------------------- ### Get Highlights Tool Source: https://github.com/iamalexander/readwise-mcp/blob/main/ARCHITECTURE.md Implementation of the GetHighlightsTool for retrieving highlights from the Readwise library with pagination and filtering capabilities. ```APIDOC ## Get Highlights Tool ### Description Retrieves highlights from your Readwise library with pagination and filtering options. ### Method POST ### Endpoint /api/get_highlights ### Parameters #### Query Parameters - **page_size** (number) - Optional - Number of highlights per page (1-1000). Defaults to 100. - **page** (number) - Optional - Page number. Defaults to 1. - **book_id** (number) - Optional - Filter by book ID. - **updated_after** (string) - Optional - ISO date string to filter by update time. ### Request Example ```json { "page_size": 50, "page": 2, "book_id": 12345, "updated_after": "2023-01-01T00:00:00Z" } ``` ### Response #### Success Response (200) - **results** (PaginatedHighlights) - An object containing the paginated list of highlights. #### Response Example ```json { "results": { "count": 100, "next": "/api/get_highlights?page=3", "previous": "/api/get_highlights?page=1", "results": [ { "id": 1, "text": "Example highlight text.", "note": "An example note.", "location": 10, "location_type": "page", "color": "yellow", "highlighted_at": "2023-10-26T10:00:00Z", "created_at": "2023-10-26T10:00:00Z", "updated_at": "2023-10-26T10:00:00Z", "book_id": 12345, "tags": [ { "id": 1, "name": "example" } ], "url": "http://example.com/highlight/1" } ] } } ``` ``` -------------------------------- ### Get Books Request Source: https://github.com/iamalexander/readwise-mcp/blob/main/examples/web-client.html Event listener for the 'Get Books' button. Constructs and sends a 'get_books' request to the MCP server using the provided page and page size. ```javascript document.getElementById('get-books-btn').addEventListener('click', function() { const page = parseInt(document.getElementById('books-page').value); const pageSize = parseInt(document.getElementById('books-page-size').value); const request = { type: 'tool_call', name: 'get_books', parameters: { page, page_size: pageSize }, request_id: `get-books-${Date.now()}` }; makeMCPRequest(request); }); ``` -------------------------------- ### Search Highlights via search_highlights Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Example tool call and response for searching highlights using a text query. ```typescript // MCP Tool Call const request = { type: 'tool_call', name: 'search_highlights', request_id: 'req-003', parameters: { query: 'productivity habits', // Required: search query limit: 20 // Optional: max results } }; // Expected Response { result: [ { highlight: { id: 'hl_456', text: 'Small habits compound over time to create remarkable results...', note: 'Key insight about habit formation', book_id: '12345', created_at: '2024-01-10T08:00:00Z' }, book: { id: '12345', title: 'Atomic Habits', author: 'James Clear' }, score: 0.95 } ], request_id: 'req-003' } ``` -------------------------------- ### Example Rate Limit Error Response Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Demonstrates a rate limit exceeded error response, which is typically auto-retried by default. ```json { error: { type: 'api', details: { status: 429, code: 'rate_limit_exceeded', message: 'Rate limit exceeded. Please wait before making more requests.' } }, request_id: 'req-003' } ``` -------------------------------- ### Initialize API Configuration and DOM Elements Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/video-features.html Sets up API base URL, token, and references to various DOM elements for UI interaction. This code should be run on page load. ```javascript // Configuration const API_BASE_URL = 'http://localhost:3000'; let apiToken = ''; let currentVideo = null; let nextPageCursor = null; let player = null; let currentTranscript = null; let currentSearchIndex = -1; let searchMatches = []; // DOM Elements const authPanel = document.getElementById('auth-panel'); const mainContent = document.getElementById('main-content'); const apiTokenInput = document.getElementById('api-token'); const authButton = document.getElementById('auth-button'); const authStatus = document.getElementById('auth-status'); const loadVideosButton = document.getElementById('load-videos'); const videoList = document.getElementById('video-list'); const loadMoreButton = document.getElementById('load-more'); const videoDetails = document.getElementById('video-details'); const videoPlayerContainer = document.getElementById('video-player-container'); const videoPlayer = document.getElementById('video-player'); const progressFill = document.getElementById('progress-fill'); const currentPositionEl = document.getElementById('current-position'); const totalDurationEl = document.getElementById('total-duration'); const progressPercentageEl = document.getElementById('progress-percentage'); const savePositionButton = document.getElementById('save-position'); const loadPositionButton = document.getElementById('load-position'); const transcript = document.getElementById('transcript'); const loadHighlightsButton = document.getElementById('load-highlights'); const highlightList = document.getElementById('highlight-list'); const createHighlightForm = document.getElementById('create-highlight-form'); const highlightText = document.getElementById('highlight-text'); const highlightTimestamp = document.getElementById('highlight-timestamp'); const highlightNote = document.getElementById('highlight-note'); const createHighlightButton = document.getElementById('create-highlight-button'); const transcriptSearchInput = document.getElementById('transcript-search'); const caseSensitiveCheckbox = document.getElementById('case-sensitive'); const wholeWordCheckbox = document.getElementById('whole-word'); const prevMatchButton = document.getElementById('prev-match'); const nextMatchButton = document.getElementById('next-match'); const matchCount = document.getElementById('match-count'); ``` -------------------------------- ### Initialize Configuration and DOM Elements Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/enhanced-transcript-features.html Sets up initial configuration variables and retrieves references to various DOM elements used throughout the application. This code should be run on page load. ```javascript // Configuration const API_BASE_URL = 'http://localhost:3000'; let apiToken = ''; let currentTranscript = null; let currentSearchIndex = -1; let searchMatches = []; // DOM Elements const authPanel = document.getElementById('auth-panel'); const mainContent = document.getElementById('main-content'); const authStatus = document.getElementById('auth-status'); const transcriptContainer = document.getElementById('transcript-container'); const searchInput = document.getElementById('search-input'); const caseSensitiveCheckbox = document.getElementById('case-sensitive'); const wholeWordCheckbox = document.getElementById('whole-word'); const prevMatchButton = document.getElementById('prev-match'); const nextMatchButton = document.getElementById('next-match'); const matchCount = document.getElementById('match-count'); ``` -------------------------------- ### Get Highlights Request Source: https://github.com/iamalexander/readwise-mcp/blob/main/examples/web-client.html Event listener for the 'Get Highlights' button. Constructs and sends a 'get_highlights' request to the MCP server using the provided book ID, page, and page size. ```javascript document.getElementById('get-highlights-btn').addEventListener('click', function() { const bookId = document.getElementById('book-id').value; const page = parseInt(document.getElementById('highlights-page').value); const pageSize = parseInt(document.getElementById('highlights-page-size').value); const request = { type: 'tool_call', name: 'get_highlights', parameters: { book_id: bookId, page, page_size: pageSize }, request_id: `get-highlights-${Date.now()}` }; makeMCPRequest(request); }); ``` -------------------------------- ### ReadwiseClient Initialization and Usage Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Demonstrates how to initialize the ReadwiseClient and use the ReadwiseAPI wrapper for making requests, including configuration options for rate limiting and retries. ```APIDOC ## ReadwiseClient Initialization and Usage ### Description The ReadwiseClient handles all HTTP communication with the Readwise API, including automatic rate limiting, exponential backoff retry for rate limit and server errors, and proper error handling. The ReadwiseAPI wrapper provides a convenient interface for interacting with the API endpoints. ### Initialization ```typescript import { ReadwiseClient } from 'readwise-mcp/api/client'; import { ReadwiseAPI } from 'readwise-mcp/api/readwise-api'; // Initialize the client with configuration const client = new ReadwiseClient({ apiKey: 'your_readwise_api_key', baseUrl: 'https://readwise.io/api/v2', // Optional, this is the default enableRateLimiting: true, // Default: true, 60 req/min maxRequestsPerMinute: 60, // Optional customization enableRetry: true, // Default: true maxRetries: 3 // Default: 3 with exponential backoff }); // Create the API wrapper const api = new ReadwiseAPI(client); ``` ### Usage Examples #### Get Highlights ```typescript const highlights = await api.getHighlights({ page_size: 50 }); console.log(`Found ${highlights.count} highlights`); ``` #### Search Highlights ```typescript const searchResults = await api.searchHighlights({ query: 'machine learning' }); console.log(`Found ${searchResults.length} matching highlights`); ``` #### Save Document ```typescript const saved = await api.saveDocument({ url: 'https://example.com/article', tags: ['research', 'AI'] }); console.log(`Saved document: ${saved.id}`); ``` ``` -------------------------------- ### Execute Development Commands Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Standard npm scripts for building, testing, and developing the project. ```bash # Build the project npm run build # Run tests npm test # Start in development mode with auto-reload npm run dev:watch # Lint code npm run lint ``` -------------------------------- ### Get Reading Progress MCP Tool Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Retrieves reading progress for a specific document by ID. ```typescript // MCP Tool Call const request = { type: 'tool_call', name: 'get_reading_progress', request_id: 'req-015', parameters: { document_id: 'doc_123' } }; // Expected Response { result: { document_id: 'doc_123', title: 'Deep Learning Fundamentals', status: 'in_progress', // 'not_started' | 'in_progress' | 'completed' percentage: 45, current_page: 180, total_pages: 400, last_read_at: '2024-06-19T20:30:00Z' }, request_id: 'req-015' } ``` -------------------------------- ### Deploy with Docker Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Commands to build and run the Readwise MCP server using Docker with SSE transport. ```bash # Build the Docker image docker build -t readwise-mcp . # Run with SSE transport on port 3001 docker run -p 3001:3001 -e READWISE_API_KEY=your_api_key readwise-mcp ``` -------------------------------- ### Run All Tests with npm Source: https://github.com/iamalexander/readwise-mcp/blob/main/tests/README.md Execute all tests in the project using the npm test command. This is the standard way to verify the server's functionality. ```bash npm test ``` -------------------------------- ### AWS Lambda Deployment Commands Source: https://github.com/iamalexander/readwise-mcp/blob/main/docs/serverless-deployment.md Commands for setting up the Serverless Framework, configuring AWS credentials, and deploying the application. ```bash npm install -g serverless ``` ```bash serverless config credentials --provider aws --key YOUR_ACCESS_KEY --secret YOUR_SECRET_KEY ``` ```bash npm run build ``` ```bash npm run sls:deploy ``` ```bash npm run sls:deploy:prod ``` -------------------------------- ### GET /get_recent_content Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Retrieves recently saved content from your Readwise library, optionally filtered by content type. ```APIDOC ## GET /get_recent_content ### Description Retrieves recently saved content from your Readwise library, optionally filtered by content type. ### Method GET ### Endpoint /get_recent_content ### Parameters #### Query Parameters - **limit** (integer) - Optional - The maximum number of results to return. - **content_type** (string) - Optional - Filters the results by content type. Allowed values: 'books', 'highlights', 'all'. Defaults to 'all'. ### Response #### Success Response (200) - **count** (integer) - The number of items returned. - **results** (array) - An array of content items. - **type** (string) - The type of content ('book' or 'highlight'). - **id** (string) - The unique identifier for the content item. - **title** (string) - The title of the content. - **author** (string) - The author of the book (if type is 'book'). - **created_at** (string) - The timestamp when the content was created. - **text** (string) - The text of the highlight (if type is 'highlight'). - **book_id** (string) - The ID of the book the highlight belongs to (if type is 'highlight'). #### Response Example ```json { "result": { "count": 10, "results": [ { "type": "book", "id": "12345", "title": "New Book Title", "author": "Author Name", "created_at": "2024-06-20T09:00:00Z" }, { "type": "highlight", "id": "hl_789", "text": "Important quote from recent reading...", "book_id": "12345", "created_at": "2024-06-20T08:30:00Z" } ] }, "request_id": "req-017" } ``` ``` -------------------------------- ### Get Recent Content MCP Tool Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Retrieves recently saved content, optionally filtered by type. ```typescript // MCP Tool Call const request = { type: 'tool_call', name: 'get_recent_content', request_id: 'req-017', parameters: { limit: 10, // Optional: max results content_type: 'all' // 'books' | 'highlights' | 'all' } }; // Expected Response { result: { count: 10, results: [ { type: 'book', id: '12345', title: 'New Book Title', author: 'Author Name', created_at: '2024-06-20T09:00:00Z' }, { type: 'highlight', id: 'hl_789', text: 'Important quote from recent reading...', book_id: '12345', created_at: '2024-06-20T08:30:00Z' } ] }, request_id: 'req-017' } ``` -------------------------------- ### GET /get_reading_progress Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Retrieves the reading progress for a specific document including status, percentage completion, and page information. ```APIDOC ## GET /get_reading_progress ### Description Retrieves the reading progress for a specific document including status, percentage completion, and page information. ### Method GET ### Endpoint /get_reading_progress ### Parameters #### Query Parameters - **document_id** (string) - Required - The ID of the document for which to retrieve reading progress. ### Response #### Success Response (200) - **document_id** (string) - The ID of the document. - **title** (string) - The title of the document. - **status** (string) - The reading status ('not_started', 'in_progress', 'completed'). - **percentage** (integer) - The percentage of the document read. - **current_page** (integer) - The current page number. - **total_pages** (integer) - The total number of pages in the document. - **last_read_at** (string) - The timestamp when the document was last read. #### Response Example ```json { "result": { "document_id": "doc_123", "title": "Deep Learning Fundamentals", "status": "in_progress", "percentage": 45, "current_page": 180, "total_pages": 400, "last_read_at": "2024-06-19T20:30:00Z" }, "request_id": "req-015" } ``` ``` -------------------------------- ### Build Docker Image Source: https://github.com/iamalexander/readwise-mcp/blob/main/ARCHITECTURE.md Dockerfile for containerizing the application for production deployment. ```dockerfile FROM node:18-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY dist/ ./dist/ ENV NODE_ENV=production ENV TRANSPORT=sse ENV PORT=3001 EXPOSE 3001 CMD ["node", "dist/index.js"] ``` -------------------------------- ### Run Readwise MCP with Docker Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Build the Docker image and run the Readwise MCP server, exposing it on port 3001 and passing the Readwise API key as an environment variable. ```bash mkdir -p ~/.readwise-mcp docker build -t readwise-mcp . docker run -p 3001:3001 -e READWISE_API_KEY=your_key readwise-mcp ``` -------------------------------- ### Example Validation Error Response Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Illustrates a validation error response, including specific validation failures in the 'errors' array. ```json { error: { type: 'validation', details: { code: 'invalid_parameters', message: 'Invalid parameters', errors: ['query: Search query is required'] } }, request_id: 'req-001' } ``` -------------------------------- ### Run Tests in Watch Mode Source: https://github.com/iamalexander/readwise-mcp/blob/main/tests/README.md Automatically re-run tests when file changes are detected. Useful during development to get quick feedback. ```bash npm run test:watch ``` -------------------------------- ### YouTube Player Ready Handler Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/video-features.html Callback function executed when the YouTube player is ready. It updates duration display and sets up an interval to track and display current playback time and progress percentage. Requires `player`, `totalDurationEl`, `formatTime`, `currentPositionEl`, `progressPercentageEl`, `progressFill`, and `highlightTimestamp`. ```javascript function onPlayerReady(event) { // Player is ready const duration = player.getDuration(); totalDurationEl.textContent = formatTime(duration); // Update current time every second setInterval(() => { if (player && player.getCurrentTime) { const currentTime = player.getCurrentTime(); const duration = player.getDuration(); const percentage = Math.round((currentTime / duration) * 100); currentPositionEl.textContent = formatTime(currentTime); progressPercentageEl.textContent = `${percentage}%`; progressFill.style.width = `${percentage}%`; // Update timestamp input if empty if (!highlightTimestamp.value) { highlightTimestamp.value = formatTime(currentTime); } } }, 1000); } ``` -------------------------------- ### Google Cloud Functions Deployment Commands Source: https://github.com/iamalexander/readwise-mcp/blob/main/docs/serverless-deployment.md Commands for authenticating with Google Cloud, setting the project, and deploying the function. ```bash gcloud auth login ``` ```bash gcloud config set project YOUR_PROJECT_ID ``` ```bash npm run build ``` ```bash gcloud functions deploy readwise-mcp \ --runtime nodejs18 \ --trigger-http \ --allow-unauthenticated \ --entry-point readwiseMcpFunction \ --source dist \ --set-env-vars READWISE_API_KEY=YOUR_API_KEY,DEBUG=false ``` -------------------------------- ### Configure Claude Desktop Source: https://github.com/iamalexander/readwise-mcp/blob/main/ARCHITECTURE.md Provides the JSON configuration for integrating the server with Claude Desktop. ```json // claude_desktop_config.json { "mcpServers": { "readwise": { "command": "npx", "args": ["-y", "readwise-mcp"], "env": { "READWISE_API_KEY": "your-api-key" } } } } ``` -------------------------------- ### Build and Run Readwise MCP with Docker Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Build the Docker image for Readwise MCP and run it as a container, exposing port 3001 and setting the Readwise API key. ```bash docker build -t readwise-mcp . docker run -p 3001:3001 -e READWISE_API_KEY=your_key readwise-mcp ``` -------------------------------- ### Test server with MCP Inspector Source: https://github.com/iamalexander/readwise-mcp/blob/main/SMITHERY.md Use the MCP Inspector tool to interact with and debug the server locally. ```bash npx @modelcontextprotocol/inspector npx @smithery/cli run server-readwise-mcp --config '{"readwiseApiToken":"your-token-here"}' ``` -------------------------------- ### Make Generic API Request Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/video-features.html A reusable function to make authenticated API requests. Handles GET, POST, PUT, DELETE methods and includes error handling. Requires `apiToken` to be set. ```javascript async function makeApiRequest(endpoint, method = 'GET', data = null) { try { const options = { method, headers: { 'Authorization': `Token ${apiToken}`, 'Content-Type': 'application/json' } }; if (data) { options.body = JSON.stringify(data); } const response = await fetch(`${API_BASE_URL}${endpoint}`, options); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'API request failed'); } return await response.json(); } catch (error) { console.error('API Error:', error); throw error; } } ``` -------------------------------- ### Find Text Matches in Transcript Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/video-features.html Searches a given text for occurrences of a query, respecting whole word and case sensitivity options. It returns an array of match objects, each with start and end indices. ```javascript function findMatches(text, query, options) { const regex = new RegExp( options.wholeWord ? `\\b${escapeRegExp(query)}\\b` : escapeRegExp(query), options.caseSensitive ? 'g' : 'gi' ); const matches = []; let match; while ((match = regex.exec(text)) !== null) { matches.push({ start: match.index, end: match.index + match[0].length }); } return matches; } ``` -------------------------------- ### Load Video Details - JavaScript Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/video-features.html Fetches and displays detailed information for a specific video, including its title, author, URL, tags, transcript, and highlights. It also sets up the YouTube player if the video is from YouTube. Call this function when a user selects a video. ```javascript async function loadVideoDetails(videoId) { try { // Highlight selected video document.querySelectorAll('.video-item').forEach(item => { item.classList.remove('active'); }); document.querySelector(`.video-item[data-id="${videoId}"]`)?.classList.add('active'); videoDetails.innerHTML = '
Loading video details...
'; transcript.innerHTML = 'Loading transcript...
'; highlightList.innerHTML = 'Loading highlights...
'; const data = await makeApiRequest(`/video/${videoId}`); currentVideo = data; // Display video details videoDetails.innerHTML = `Author: ${data.author || 'Unknown'}
Source: ${data.url}
Added: ${new Date(data.created_at).toLocaleDateString()}
Tags: ${data.tags?.join(', ') || 'None'}
`; // Setup YouTube player if it's a YouTube video if (data.url && (data.url.includes('youtube.com') || data.url.includes('youtu.be'))) { setupYouTubePlayer(data.url); } else { videoPlayerContainer.classList.add('hidden'); } // Display transcript loadTranscript(videoId); // Load highlights loadHighlights(videoId); // Show highlight form createHighlightForm.classList.remove('hidden'); loadHighlightsButton.classList.remove('hidden'); } catch (error) { showError(videoDetails, 'Failed to load video details: ' + error.message); transcript.innerHTML = 'Failed to load transcript.
'; highlightList.innerHTML = 'Failed to load highlights.
'; } } ``` -------------------------------- ### Execute Test Commands Source: https://github.com/iamalexander/readwise-mcp/blob/main/ARCHITECTURE.md Lists common CLI commands for running tests and generating coverage reports. ```bash # Run all tests npm test # Watch mode npm run test:watch # Coverage report npm run test:coverage # Specific test file npm test -- tests/tools/get-highlights.test.ts ``` -------------------------------- ### Register a New Tool in Server Source: https://github.com/iamalexander/readwise-mcp/blob/main/ARCHITECTURE.md Register the newly created tool instance with the tool registry in the server configuration. ```typescript import { MyNewTool } from './tools/my-new-tool'; // In constructor or setup method: this.toolRegistry.register(new MyNewTool(this.api, this.logger)); ``` -------------------------------- ### Run the Fixed Readwise Server Source: https://github.com/iamalexander/readwise-mcp/blob/main/examples/README.md Compiles the TypeScript source and executes the Readwise MCP server using Node.js. ```bash # Compile TypeScript first npx tsc # Run the server node dist/examples/run-fixed-readwise-server.js ``` -------------------------------- ### Create YouTube Player Instance Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/video-features.html Creates a new YouTube player instance within a specified div. Clears any previous player content. Requires `playerDiv`, `YT.Player`, `onPlayerReady`, and `onPlayerStateChange`. ```javascript function createYouTubePlayer(videoId) { // Clear previous player videoPlayer.innerHTML = ''; // Create player div const playerDiv = document.createElement('div'); playerDiv.id = 'youtube-player'; videoPlayer.appendChild(playerDiv); // Create player player = new YT.Player('youtube-player', { height: '360', width: '640', videoId: videoId, events: { 'onReady': onPlayerReady, 'onStateChange': onPlayerStateChange } }); } ``` -------------------------------- ### CLI Entry Point Responsibilities Source: https://github.com/iamalexander/readwise-mcp/blob/main/ARCHITECTURE.md Outlines the core tasks performed by the CLI entry point in src/index.ts. ```typescript // Responsibilities - Parse CLI arguments (--port, --transport, --debug, --api-key, --setup) - Load configuration from environment/files - Initialize logging with appropriate level - Create and start ReadwiseMCPServer instance - Handle graceful shutdown on SIGINT/SIGTERM ``` -------------------------------- ### Claude Desktop MCP Server Configuration Source: https://github.com/iamalexander/readwise-mcp/blob/main/README.md Configuration for adding the Readwise MCP server to Claude Desktop. Ensure you replace 'your_api_key_here' with your actual Readwise API key. ```json { "mcpServers": { "readwise": { "command": "readwise-mcp", "env": { "READWISE_API_KEY": "your_api_key_here" } } } } ``` -------------------------------- ### Initialize ReadwiseClient Source: https://context7.com/iamalexander/readwise-mcp/llms.txt Configures the ReadwiseClient with API keys and rate limiting settings, then uses the ReadwiseAPI wrapper for operations. ```typescript import { ReadwiseClient } from 'readwise-mcp/api/client'; import { ReadwiseAPI } from 'readwise-mcp/api/readwise-api'; // Initialize the client with configuration const client = new ReadwiseClient({ apiKey: 'your_readwise_api_key', baseUrl: 'https://readwise.io/api/v2', // Optional, this is the default enableRateLimiting: true, // Default: true, 60 req/min maxRequestsPerMinute: 60, // Optional customization enableRetry: true, // Default: true maxRetries: 3 // Default: 3 with exponential backoff }); // Create the API wrapper const api = new ReadwiseAPI(client); // Use the API directly const highlights = await api.getHighlights({ page_size: 50 }); console.log(`Found ${highlights.count} highlights`); const searchResults = await api.searchHighlights({ query: 'machine learning' }); console.log(`Found ${searchResults.length} matching highlights`); // Save a new document const saved = await api.saveDocument({ url: 'https://example.com/article', tags: ['research', 'AI'] }); console.log(`Saved document: ${saved.id}`); ``` -------------------------------- ### Project Directory Structure Source: https://github.com/iamalexander/readwise-mcp/blob/main/ARCHITECTURE.md Visual representation of the project's file and folder hierarchy. ```text readwise-mcp/ ├── src/ # Source code │ ├── index.ts # CLI entry point │ ├── server.ts # Main server class │ ├── constants.ts # Application constants │ │ │ ├── api/ # Readwise API integration │ │ ├── client.ts # HTTP client with rate limiting │ │ └── readwise-api.ts # High-level API wrapper │ │ │ ├── mcp/ # MCP protocol implementation │ │ └── registry/ # Tool and prompt registries │ │ ├── tool-registry.ts # Tool management │ │ ├── prompt-registry.ts # Prompt management │ │ ├── base-tool.ts # Abstract tool base class │ │ └── base-prompt.ts # Abstract prompt base class │ │ │ ├── tools/ # MCP tool implementations (40+) │ │ ├── get-highlights.ts # Highlight retrieval │ │ ├── get-books.ts # Book retrieval │ │ ├── get-documents.ts # Document retrieval │ │ ├── search-highlights.ts # Highlight search │ │ ├── create-highlight.ts # Create highlight │ │ ├── update-highlight.ts # Update highlight │ │ ├── delete-highlight.ts # Delete highlight │ │ ├── save-document.ts # Save document/URL │ │ ├── bulk-*.ts # Bulk operations │ │ ├── video-*.ts # Video operations │ │ └── ... # Additional tools │ │ │ ├── prompts/ # MCP prompt implementations │ │ ├── highlight-prompt.ts # Highlight analysis prompt │ │ └── search-prompt.ts # Search results prompt │ │ │ ├── types/ # TypeScript type definitions │ │ ├── index.ts # Core types export │ │ ├── readwise.ts # Readwise data models │ │ ├── mcp.ts # MCP protocol types │ │ ├── errors.ts # Error types │ │ └── validation.ts # Validation types and helpers │ │ │ └── utils/ # Utility modules │ ├── logger.ts # Standard logger │ ├── safe-logger.ts # MCP-safe logger │ ├── config.ts # Configuration management │ └── rate-limiter.ts # Rate limiting utilities │ ├── tests/ # Test suite │ ├── setup.ts # Test configuration │ ├── api/ # API layer tests │ ├── tools/ # Tool tests │ ├── prompts/ # Prompt tests │ ├── types/ # Type/validation tests │ └── utils/ # Utility tests │ ├── examples/ # Example implementations ├── docs/ # Additional documentation ├── bin/ # Binary/CLI files │ ├── package.json # Dependencies and scripts ├── tsconfig.json # TypeScript configuration ├── jest.config.cjs # Jest configuration └── eslint.config.js # ESLint configuration ``` -------------------------------- ### Run Comprehensive MCP Server Tests Source: https://github.com/iamalexander/readwise-mcp/blob/main/test-scripts/README.md Execute the main test script to verify both stdio and SSE transports, including cleanup, health checks, and logging. ```bash ./smart-mcp-test.sh ``` -------------------------------- ### Load Video List - JavaScript Source: https://github.com/iamalexander/readwise-mcp/blob/main/demo/video-features.html Fetches a list of videos from the API and renders them. Handles pagination and displays a 'load more' button if more videos are available. Use this function to populate the initial video list. ```javascript async function loadVideos() { try { const data = await makeApiRequest('/videos'); data.videos.forEach(video => { const videoItem = document.createElement('div'); videoItem.className = 'video-item'; videoItem.dataset.id = video.id; videoItem.innerHTML = ` ${video.title}