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 };
    });
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It mentions searching across collections and example query types, but lacks details on permissions, rate limits, error handling, or result format. It adds some context but doesn't fully disclose behavioral traits for a search tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences, front-loaded with core purpose, followed by usage context and examples. Every sentence adds value: first defines the tool, second specifies scope and use case, third provides concrete examples. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a search tool with 3 parameters, 100% schema coverage, and no output schema, the description is reasonably complete. It covers purpose, usage, and scope, though could benefit from mentioning result structure or limitations. Good given the structured data available.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters. The description implies keyword/phrase searching and collection options but doesn't add syntax or format details beyond what the schema provides. Baseline 3 is appropriate when schema does the heavy lifting.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool searches Hadith collections by keywords/phrases, distinguishing it from siblings like get_hadith (likely by ID), search_hadith_by_topic (topic-based), and search_quran (different resource). It specifies the verb 'search' and resource 'Hadith collections' with scope across major collections.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use: 'Find hadiths about specific topics without knowing exact hadith numbers' and 'Perfect for queries like...'. Distinguishes from alternatives by mentioning search across all or specific collections, contrasting with sibling tools like search_hadith_by_topic.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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