Skip to main content
Glama
ispyridis

Calibre RAG MCP Server

by ispyridis

search

Search your Calibre ebook library using natural language queries or field-specific metadata syntax to find books by content or attributes.

Instructions

Search the Calibre ebook library. Supports both full-text content search (default) and metadata search using field syntax.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query. For full-text: use natural language. For metadata: use field syntax (author:Name, title:"Title").
limitNoMaximum number of results (default: 50)
fuzzy_fallbackNoAlternative search terms if exact query fails

Implementation Reference

  • Core handler function that executes the book search using Calibre's 'calibredb search' and 'list' commands, fetches metadata, and formats results with epub URLs.
    async searchBooksMetadata(query, limit = 50) {
        try {
            const searchResult = await this.runCalibreCommand(['search', '--limit', limit.toString(), query]);
            
            if (!searchResult.trim()) {
                return [];
            }
    
            const bookIds = searchResult.trim();
            const idQuery = `id:${bookIds.replace(/,/g, ' OR id:')}`;
            
            const listResult = await this.runCalibreCommand([
                'list',
                '--fields', 'id,title,authors,series,tags,publisher,pubdate,formats,identifiers,comments',
                '--for-machine',
                '--search', idQuery
            ]);
    
            const books = JSON.parse(listResult || '[]');
            
            return books.map(book => ({
                id: book.id,
                title: book.title,
                authors: book.authors,
                series: book.series,
                tags: book.tags,
                publisher: book.publisher,
                published: book.pubdate,
                epub_url: this.createEpubUrl(book.authors, book.title, book.id),
                formats: book.formats ? book.formats.map(f => path.basename(f)) : [],
                full_formats: book.formats || [],
                has_text: book.formats ? book.formats.some(f => f.endsWith('.txt')) : false,
                description: book.comments ? 
                    book.comments.replace(/<[^>]+>/g, '').split('\n').slice(0, 2).join(' ').substring(0, 200) + '...' : 
                    null
            }));
            
        } catch (error) {
            this.log(`Metadata search failed: ${error.message}`);
            return [];
        }
    }
  • Input schema defining parameters for the 'search' tool: query (required), limit, fuzzy_fallback.
    inputSchema: {
        type: 'object',
        properties: {
            query: {
                type: 'string',
                description: 'Search query. For full-text: use natural language. For metadata: use field syntax (author:Name, title:"Title").'
            },
            limit: {
                type: 'integer',
                description: 'Maximum number of results (default: 50)',
                default: 50
            },
            fuzzy_fallback: {
                type: 'string',
                description: 'Alternative search terms if exact query fails'
            }
        },
        required: ['query']
    }
  • server.js:966-987 (registration)
    Registration of the 'search' tool in the static tools array returned by 'tools/list' method.
        name: 'search',
        description: 'Search the Calibre ebook library. Supports both full-text content search (default) and metadata search using field syntax.',
        inputSchema: {
            type: 'object',
            properties: {
                query: {
                    type: 'string',
                    description: 'Search query. For full-text: use natural language. For metadata: use field syntax (author:Name, title:"Title").'
                },
                limit: {
                    type: 'integer',
                    description: 'Maximum number of results (default: 50)',
                    default: 50
                },
                fuzzy_fallback: {
                    type: 'string',
                    description: 'Alternative search terms if exact query fails'
                }
            },
            required: ['query']
        }
    },
  • Tool dispatch handler in 'tools/call' that validates input, calls searchBooksMetadata, formats response, and sends MCP success response.
    case 'search':
        const query = args.query;
        const limit = args.limit || 50;
        
        if (!query) {
            this.sendError(id, -32602, 'Missing required parameter: query');
            return;
        }
        
        const results = await this.searchBooksMetadata(query, limit);
        const mcpResult = this.formatResponse(results, query, 'search');
        this.sendSuccess(id, mcpResult);
        break;
  • Helper function to format search results into MCP-compatible response structure with text summary and structured results.
    }
    
    formatResponse(searchResults, query, searchType = 'search') {

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/ispyridis/calibre-rag-mcp-nodejs'

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