Skip to main content
Glama

search_hadith

Search Islamic Hadith collections by keywords or phrases to find teachings on specific topics like prayer, charity, or manners across major collections including Bukhari and Muslim.

Instructions

Search Hadith collections by keywords or phrases. Find hadiths about specific topics without knowing exact hadith numbers. Search across all major collections (Bukhari, Muslim, Abu Dawud, Tirmidhi, Nasai, Ibn Majah) or specific ones. Perfect for queries like "prayer times", "charity", "manners", etc.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query - keywords or phrases to search for in hadiths. Minimum 2 characters.
collectionsNoSpecific collections to search in (optional). If not specified, searches all collections. Options: bukhari, muslim, abudawud, tirmidhi, nasai, ibnmajah
max_resultsNoMaximum number of results to return (default: 20, max: 50)

Implementation Reference

  • The primary handler function implementing the search_hadith tool. Performs advanced fuzzy keyword search across specified Hadith collections using relevance scoring, Levenshtein distance for similarity, Arabic normalization, parallel API calls, and intelligent sampling for efficient results.
    export async function searchHadith( query: string, collections?: string[], maxResults: number = 20 ): Promise<HadithSearchResult[]> { if (!query || query.trim().length < 2) { throw new QuranMCPError( 'Search query must be at least 2 characters long', 'INVALID_SEARCH_QUERY' ); } // Validate collections const searchCollections = collections && collections.length > 0 ? collections : HADITH_COLLECTIONS.map(c => c.slug); for (const col of searchCollections) { if (!HADITH_COLLECTIONS.find(c => c.slug === col)) { throw new QuranMCPError( `Unknown collection: ${col}. Available: ${HADITH_COLLECTIONS.map(c => c.slug).join(', ')}`, 'INVALID_COLLECTION' ); } } const cacheKey = `search:hadith:${searchCollections.join(',')}:${query}:${maxResults}`; return searchCacheService.getOrSet(cacheKey, async () => { const results: HadithSearchResult[] = []; const keywords = query.toLowerCase().split(/\s+/).filter(k => k.length > 1); const isArabicQuery = isArabic(query); // AGGRESSIVE optimization: Much smaller sample size, more parallel requests const SAMPLE_SIZE = 50; // Reduced from 200 to 50 for speed const PARALLEL_REQUESTS = 10; // Increased from 5 to 10 for speed const MAX_COLLECTIONS = 2; // Only search first 2 collections by default // Limit collections for performance const limitedCollections = searchCollections.slice(0, MAX_COLLECTIONS); // Process all collections in parallel const collectionPromises = limitedCollections.map(async (collectionSlug) => { const collectionInfo = HADITH_COLLECTIONS.find(c => c.slug === collectionSlug); if (!collectionInfo) return []; const collectionResults: HadithSearchResult[] = []; const sampleSize = Math.min(SAMPLE_SIZE, collectionInfo.totalHadiths); const step = Math.max(1, Math.floor(collectionInfo.totalHadiths / sampleSize)); // Create array of hadith numbers to search const hadithNumbers: number[] = []; for (let i = 1; i <= collectionInfo.totalHadiths && hadithNumbers.length < sampleSize; i += step) { hadithNumbers.push(i); } // Process ALL hadiths in parallel batches for (let i = 0; i < hadithNumbers.length; i += PARALLEL_REQUESTS) { const batch = hadithNumbers.slice(i, i + PARALLEL_REQUESTS); const batchPromises = batch.map(async (hadithNum) => { try { // Fetch Arabic if query is Arabic, otherwise fetch English const lang = isArabicQuery ? 'ara' : 'eng'; const url = `${API_ENDPOINTS.HADITH}/${lang}-${collectionSlug}/${hadithNum}.json`; const data = await fetchJSON<any>(url); if (!data) return null; // Handle the actual API structure: { metadata: {...}, hadiths: [{text: "..."}] } let text = ''; let book = undefined; let chapter = undefined; if (data.hadiths && Array.isArray(data.hadiths) && data.hadiths.length > 0) { // Find the hadith with matching number const hadith = data.hadiths.find((h: any) => h.hadithnumber === hadithNum) || data.hadiths[0]; text = hadith.text || ''; book = hadith.reference?.book; chapter = data.metadata?.section?.[book]; } else { // Fallback to old structure text = data.text || data.hadith || ''; book = data.book; chapter = data.chapter || data.chapterName; } if (!text || text.trim().length === 0) return null; const { score, matchType } = calculateRelevance(text, keywords); if (score > 0) { return { hadithNumber: hadithNum, collection: collectionSlug, collectionName: collectionInfo.name, text, book, chapter, relevanceScore: score, matchType, }; } } catch { // Silently fail and continue } return null; }); const batchResults = await Promise.all(batchPromises); collectionResults.push(...batchResults.filter(r => r !== null) as HadithSearchResult[]); // Early exit if we have enough high-quality results for this collection if (collectionResults.filter(r => r.matchType === 'exact').length >= maxResults) { break; } } return collectionResults; }); // Wait for all collections to finish const allCollectionResults = await Promise.all(collectionPromises); results.push(...allCollectionResults.flat()); // Sort by relevance and match type const sorted = results.sort((a, b) => { // Prioritize exact matches if (a.matchType === 'exact' && b.matchType !== 'exact') return -1; if (b.matchType === 'exact' && a.matchType !== 'exact') return 1; // Then by score return b.relevanceScore - a.relevanceScore; }); const finalResults = sorted.slice(0, maxResults); // Add helpful message if no results or only fuzzy matches if (finalResults.length === 0) { console.log(`No hadiths found for "${query}". Try different keywords or check spelling.`); } else if (finalResults.every(r => r.matchType !== 'exact')) { console.log(`No exact matches for "${query}". Showing ${finalResults.length} similar hadiths.`); } return finalResults; });
  • JSON Schema definition for the search_hadith tool input validation, including parameters query, collections (array of strings), and max_results.
    { name: 'search_hadith', description: 'Search Hadith collections by keywords or phrases. Find hadiths about specific topics without knowing exact hadith numbers. Search across all major collections (Bukhari, Muslim, Abu Dawud, Tirmidhi, Nasai, Ibn Majah) or specific ones. Perfect for queries like "prayer times", "charity", "manners", etc.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query - keywords or phrases to search for in hadiths. Minimum 2 characters.', }, collections: { type: 'array', description: 'Specific collections to search in (optional). If not specified, searches all collections. Options: bukhari, muslim, abudawud, tirmidhi, nasai, ibnmajah', items: { type: 'string', enum: ['bukhari', 'muslim', 'abudawud', 'tirmidhi', 'nasai', 'ibnmajah'], }, }, max_results: { type: 'number', description: 'Maximum number of results to return (default: 20, max: 50)', default: 20, maximum: 50, }, }, required: ['query'], }, },
  • Registration and dispatch logic in the shared tool executor. Handles tool calls for 'search_hadith' by extracting arguments and invoking the searchHadith handler.
    case 'search_hadith': { const { query, collections, max_results = 20 } = args; result = await searchHadith(query, collections, max_results); break;
  • MCP tools/list handler in HTTP server that returns the full tools list including search_hadith.
    function handleMcpToolsList(id: string | number | null): JsonRpcResponse { return createJsonRpcResponse(id, { tools: tools, }); }
  • src/index.ts:38-40 (registration)
    MCP tools/list handler in stdio server that registers all tools including search_hadith.
    server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools }; });

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/Prince77-7/quranMCP'

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