Quran Gallery MCP
this is duplicate of the https://glama.ai/mcp/connectors/com.qurangallery/mcp
Server Details
Hosted, no-account MCP server for the classical Islamic library (Maktabah al-Shamela, 8,594 books): search and read hadith, tafsir, fiqh and other classical works, returning verbatim Arabic text cited by printed volume and page. Optional free API key for higher limits. Docs: https://github.com/qurangallery/kb-mcp
- Status
- Healthy
- Uptime
- 99.8% over 25 days
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- ChatGPT
- –
- Claude
- –
TDQS
Scored across 15 tools
The set has three search entry points (search, shamela_search, shamela_search_library) and two reading tools (fetch, shamela_read), which are inherently overlapping. However, every description carries explicit routing rules ("Instead: …", "Use shamela_search … to pin books") and states which tool is the default for which question, so an agent can usually pick correctly.
The bulk of the set uses a clear shamela_verb_noun pattern (shamela_search, shamela_read, shamela_find, shamela_get_details, shamela_lookup_hadith, shamela_verify_quote), with lookup_* forming a coherent sub-family. The two unprefixed generic tools (fetch, search) break the prefix convention, but the deviation is deliberate and readable.
15 tools sit at the top of the well-scoped range and the domain (Qur'an, hadith, rijal, tafsir, catalogue, citation, verification) justifies most of them. The count is slightly inflated by the generic search/fetch passthroughs and the meta shamela_get_brief, which duplicate or support rather than extend the research surface.
The surface covers the full read-only research lifecycle: catalogue discovery, full-text search, page/section/volume reading, verse and hadith lookup, narrator/isnad analysis, tafsir coverage, citation building, quote verification, and topic sizing. No obvious dead ends remain for a library-reading domain.
Available Tools
15 toolsfetchRead a library pageARead-onlyIdempotentInspect
Read one library page whole by the id search returned: main text, then its footnotes under their own label (the editor's words, never the author's), with book, author, printed volume/page, edition data and the link to the page in the Quran Gallery Maktabah reader. Use shamela_read instead to read one body part at a time (unit "page"), a run of pages (unit "range") or a whole chapter (unit "section"), and shamela_cite (mode "printed_page") to turn a printed volume and page into ids. Not a search. Long pages are cut at 4 body parts of about 4,000 characters (2 without an API key): metadata.complete false, ending with the shamela_read call that continues it. A malformed id, or a page the library does not hold, returns a tool error.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Page id "{bookId}:{pageId}", e.g. "1681:10" — Shamela internal ids from a `search` result, not printed page numbers. Malformed or unknown ids return a tool error. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | "{bookId}:{pageId}", normalised. |
| url | No | The same page in the Quran Gallery Maktabah reader. |
| text | No | Main text, then the footnotes under their own label (the editor's words). When metadata.complete is false it ends with the shamela_read(unit='page') call that continues it. |
| title | No | "{book} — {author} ({volume}/{page})". |
| metadata | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/idempotent annotations by disclosing truncation behavior (4 body parts, ~4,000 chars, 2 without an API key), the metadata.complete=false signal, and the continuation call shamela_read. It also states error behavior for malformed or unheld ids. Slight gap: "the editor's words, never the author's" for footnotes is evocative but not fully operationalized.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Information-dense and front-loaded with the core action, and every clause carries distinct information. However, the middle is a long run-on sentence with nested em-dash asides, which costs readability for an agent parsing quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Output schema exists, so return values need not be spelled out, yet the description still flags the truncation/continuation contract that the schema cannot express. Combined with the error semantics and sibling routing, nothing needed to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description earns above that by tying the id to a `search` result in prose and pointing to shamela_cite mode "printed_page" as the conversion path from printed references. It reinforces the id-derivation constraint rather than restating the format alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Read one library page whole by the id") and enumerates exactly what comes back: main text, footnotes under their own label, book/author/volume/page/edition metadata, and reader link. It distinguishes itself from siblings both positively (shamela_read, shamela_cite) and negatively ("Not a search").
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: use shamela_read for unit "page", "range", or "section"; use shamela_cite mode "printed_page" to convert printed references into ids; this tool is not for searching. The agent knows precisely when this tool is and is not the right choice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchQuick generic search of the whole libraryARead-onlyIdempotentInspect
Search the whole classical Islamic library (8,594 works, no scope) and get up to 10 pages as {id, title, url}; pass an id to fetch to read the page. This is the generic one-argument entry (the standard search/fetch pair); the scoped tools answer research questions better. Use shamela_search_library for a hadith, tafsir or fiqh question: unscoped ranking is by term frequency, so a poetry anthology can outrank Sahih al-Bukhari. Use shamela_search (match "words", "phrase", "near", "exact" or "boolean") to pin books, categories or a madhhab, match an exact or diacritized phrase, or page further; use shamela_cite (mode "printed_page") for printed-page citations. Exact phrase first; only when it finds nothing are the words matched separately. Title flags: [footnote match] = only an editor's footnote; [token match] = words occur apart; [near match] = only some words or their roots. Empty results mean no page carries the words. A query without Arabic words returns a tool error.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Arabic search text, e.g. "إنما الأعمال بالنيات"; 2-6 words work best. Quote the wording if known, else name the topic. |
Output Schema
| Name | Required | Description |
|---|---|---|
| results | No | At most 10 pages; empty when no page carries the words. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, closed-world, but the description adds substantial behavioral context beyond them: a hard cap of 10 pages, the exact return shape, ranking being term-frequency based, the exact-phrase-first-then-split-words fallback, the meaning of the three title flags ([footnote match], [token match], [near match]), that empty results mean no page carries the words, and that a query with no Arabic words raises a tool error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence front-loads the tool's identity, scope, and return contract, and every subsequent sentence carries real information. It is dense and slightly long, with the title-flag glossary and match-fallback detail sitting between the alternative-tool routing and the error note rather than in a clean order, but nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Although an output schema exists and return values need not be explained, the description still covers limits, ranking, fallback matching, flag meanings, and error behavior for a single-parameter read tool. Nothing an agent needs to call it correctly or interpret empty results is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single `query` parameter's description already specifies Arabic text, an example, and the 2–6 word sweet spot, so the baseline is 3. The description adds one genuinely new constraint not in the schema — that a query without Arabic words returns a tool error — but otherwise does not add syntax or matching-mode detail to the parameter itself.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb, resource, and scope: search the whole classical Islamic library across 8,594 works with no filtering, returning up to 10 {id, title, url} pages that chain into `fetch`. It explicitly positions itself as the generic one-argument entry in the search/fetch pair and names the scoped siblings that answer research questions better, so an agent can separate it from shamela_search and shamela_search_library without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit routing rules: use shamela_search_library for hadith/tafsir/fiqh questions because unscoped ranking is by term frequency and a poetry anthology can outrank Sahih al-Bukhari; use shamela_search to pin books, categories, or a madhhab, match exact/diacritized phrases, or paginate; use shamela_cite with mode "printed_page" for citations. The condition that selects each alternative is stated, not implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_citeFormat a citation or resolve a printed pageARead-onlyIdempotentInspect
Citations. mode=citation (default): build one for a book, optionally a page and quoted text — Shamela's copy format, short inline, full with death year, or BibTeX/RIS. Call it whenever you attribute a quote; it needs only the catalogue, plus the installed text for a page's printed number. Read page_resolved, components.auto_numbered and notes[] before presenting.
mode=printed_page: map a printed citation («vol. 4, p. 405») to the page_ids carrying it — no arithmetic relates the two, and one printed page often spans several ids: read them all, in order, with shamela_read(unit='page'). Resolve the work with shamela_find(kind='work') first; holding a page_id already, skip this. Failures come back as status; citable:false = Shamela's own numbering. Error: BOOK_NOT_FOUND.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Selects what the call does: citation | printed_page. Default citation. | |
| page | No | The PRINTED page number as the citation gives it (e.g. 405). Example: {book_id:6910, part:'4', page:405}; {book_id:1681, part:'1', page:6}. (mode=printed_page only.) | |
| part | No | The volume/part label as the book uses it, usually a bare number ('4'). Omit when the citation names no volume or the work is single-volume: the search then runs across every part and the response reports which parts matched, so an ambiguous page number is visible rather than silently resolved to the first volume. (mode=printed_page only.) | |
| text | No | Optional quoted text. Used by the 'shamela' style only, which then prints a two-line block: «<book>» (<part>/ <page>): «<text>». Other styles ignore it. (mode=citation only.) | |
| style | No | Citation style. 'shamela' replicates Shamela's UI copy-with-citation format (default). 'short' is a one-line inline reference. 'full' is the long form including author death year and book year, with notes listing missing fields (publisher/edition/etc are not in master.db). 'bibtex' and 'ris' are machine-readable exports for Zotero/EndNote/Mendeley (Western digits, Arabic UTF-8, stable cite key shamela<book_id>p<page_id>); they carry only fields master.db has, with the same missing-field notes[]. 'short' reads <author>، <book>، ص <page>. Every style but bibtex/ris uses Arabic-Indic digits. (mode=citation only.) | |
| book_id | No | [mode=citation] The book id, from shamela_find(kind='book'), shamela_find(kind='work') or shamela_find(kind='name'). [mode=printed_page] The book. Resolve a cited title with shamela_find(kind='work') first — and note that different printings of one work paginate differently, so the book_id must be the printing the citation came from. | |
| page_id | No | Optional page_id. When omitted, the citation references the book without a specific page and page_resolved is null. A page id that is missing, has no printed number, or belongs to a book whose text is not installed here yields a book-level citation with page_resolved:false and a note. Example: {book_id:1681, page_id:10}, or with text:'<quoted passage>', style:'shamela'. (mode=citation only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). |
Output Schema
| Name | Required | Description |
|---|---|---|
| notes | No | [mode=citation] Missing citation fields and fallbacks; never fill them in. [mode=printed_page] Guidance on reading the result. |
| style | No | 'shamela', 'short', 'full', 'bibtex' or 'ris'. (mode=citation only.) |
| status | No | 'ok', 'book_not_downloaded', 'no_printed_pagination' (Shamela paginates this entry itself: no printed page exists), 'part_not_found' or 'page_not_in_part'. (mode=printed_page only.) |
| book_id | No | Catalogue book id. (mode=printed_page only.) |
| citable | No | False when the numbers are Shamela's own, not a printed edition's. (mode=printed_page only.) |
| matches | No | One row per page id. (mode=printed_page only.) |
| page_ids | No | Every page id carrying the printed page, in reading order; read them all. Shamela splits a long printed page across records, so one page routinely has several ids (part '1', page 6 of book 1681 = ids 9, 10, 11 in the fixture). (mode=printed_page only.) |
| book_name | No | Catalogue title of the book (Arabic). (mode=printed_page only.) |
| formatted | No | The citation text in the requested style. (mode=citation only.) |
| truncated | No | |
| components | No | The parts the citation was built from. (mode=citation only.) |
| page_range | No | On page_not_in_part: the printed range that exists in that part. (mode=printed_page only.) |
| rows_dropped | No | |
| page_resolved | No | True when the page and its printed number were found; false when the citation fell back to book level (see notes) and must not be presented as a page reference; null when no page_id was given. (mode=citation only.) |
| parts_matched | No | Distinct parts matched; more than one means the number is ambiguous across volumes. (mode=printed_page only.) |
| requested_page | No | Printed page requested. (mode=printed_page only.) |
| requested_part | No | Part label requested; null when omitted. (mode=printed_page only.) |
| available_parts | No | On part_not_found: the part labels the book uses. (mode=printed_page only.) |
| truncation_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, but the description adds behavior beyond them: failures surface via `status`, citable:false means Shamela's own numbering, BOOK_NOT_FOUND as an error, no arithmetic links printed number to page_id, and one printed page often spans several ids. It also flags which output fields (page_resolved, components.auto_numbered, notes[]) to inspect, though this overlaps somewhat with the existing output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads mode=citation before mode=printed_page and every sentence carries information. It is dense to the point of being hard to parse (fragments like 'Citations.', heavy em-dashes and « » glyphs), so it is efficient but not maximally scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, two-mode tool with an output schema, the description covers both modes, their dependencies, error surfaces, and the ambiguity case (omitting `part` reports matched parts instead of silently resolving). Nothing an agent needs in order to call it correctly appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema itself already annotates mode-specific applicability ('mode=citation only') and the full style enum. The description's parameter-level contribution is largely redundant ('it needs only the catalogue, plus the installed text'), so the baseline 3 applies even though the description is well-written.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The title and first paragraph state specific verbs and resources for both modes: mode=citation builds a citation for a book/page, mode=printed_page maps a printed citation to page_ids. It explicitly separates the two behaviors and names the sibling tools (shamela_find, shamela_read) it cooperates with, so an agent can distinguish it from the lookup and read tools without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use ('Call it whenever you attribute a quote') and explicit routing ('Resolve the work with shamela_find(kind=work) first; holding a page_id already, skip this'), plus a mode-selection rule (holding a page_id → skip printed_page). Alternatives and their preconditions are named rather than left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_findFind books, headings, authors, categories or namesARead-onlyIdempotentInspect
Catalogue lookup — which books, headings, authors and shelves exist, not page text. kind:
book (default): titles, authors, publication lines, subject descriptions → book_ids, installed or not. no_title_match: not proof the book is held. downloaded:false → another edition (shamela_get_details(kind='book') same_group) or catalogue metadata only.
heading: chapter/section headings, i.e. where books treat a topic; open with shamela_read(unit='section', book_id, title_id). No hits = no heading carries the words: drop words or use shamela_search(match='words').
author: names and biographies → author_id, Hijri death year, book count; no scope. Empty is not absence: retry kunya, nisba or shuhra (ابن قدامة / الموفق / المقدسي).
category: the 41 flat shelves with catalogue and installed counts → scope.category_ids. A subject spans ids (Qur'anic studies 3 tafsir, 4 Qur'anic sciences/usul al-tafsir, 5 tajwid/qira'at; fiqh 14–17 by madhab): pass all that apply. downloaded_only:true when choosing shelves to search or read.
work: verify a cited title (optional author, edition); refuses rather than guesses; catalogue only, text need not be installed.
name: fuzzy best guess over book/author names, for an id; always answers, so never use it to verify a citation.
period: books by Hijri window, bounds ANDed (scope.period_* on searches unions them). Rules: a parameter of another kind is refused; book/heading/author/period page with limit/offset until has_more is false. Instead: page text → shamela_search; a printed page → shamela_cite(mode='printed_page'); one book's headings → shamela_read(unit='toc').
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Selects what the call does: book | heading | author | category | work | name | period. Default book. | |
| type | No | 'book' matches catalogue titles only, 'author' author names only, 'any' (default) both, returned as separate books[] and authors[] lists. Reads the s_book/ and s_author/ n-gram indexes (fast partial matching). Example: {query:'ابن قدامة', type:'author'}. (kind=name only.) | |
| limit | No | [kind=book|heading|author|period] Maximum number of results to return (1-100, default 20). [kind=work] Maximum candidates to report (1-50, default 20). [kind=name] Maximum results per list (1–20, default 5): with type 'any' you get up to `limit` books AND up to `limit` authors. (kind=book|heading|author|work|name|period only.) | |
| query | No | [kind=book] Arabic words matched against book name + author + bibliography and the editorial subject description; each hit's `matched_in` says which. 1,729 entries carry a description (~1,500 characters on average), which finds a book by SUBJECT: «الرجز» matches 0 titles and 2 descriptions; {query:'البيوع'} also returns books whose description carries it. E.g. {query:'الأصول'}. [kind=heading] Arabic words matched against chapter / section title text, e.g. 'باب الصيام', or 'تعريف' with scope:{book_ids:[id]}. [kind=author] Arabic words matched against name + biography in the ~3,200-author catalogue, e.g. 'ابن قدامة'. [kind=name] An Arabic name fragment: 'ابن قدامة' resolves Ibn Qudamah, 'روضة الناظر' the book, 'الروضة' the books with that word in their title; «title لِauthor» is split into title and author. Every kind reads pre-built indexes: no download needed. (kind=book|heading|author|name only.) | |
| scope | No | [kind=book] Restrict to authors, categories, a Hijri period (period_from/period_to) or downloaded_only (books whose text is installed); scope.book_ids is not accepted. E.g. {query:'فقه', scope:{category_ids:[17], downloaded_only:true}}. [kind=heading] The same filter as shamela_search(match='words'); scope.book_ids with one id searches only that book's headings. EMPTY_SCOPE: the scope matched no book. (kind=book|heading only.) | |
| title | No | The work's title as cited, e.g. «صحيح البخاري», «المغني», «فتح الباري». Leading words only — the title, not a description of it. You may include the catalogue's own edition tail, with the « - » («صحيح البخاري - ط السلطانية») or without it («مسند أحمد ط الرسالة»), and it will be read as `edition`. An author name appended instead («صحيح البخاري محمد بن إسماعيل البخاري», «الهداية للمرغيناني») is read as `author`. Where a title is held by more than one author, a trailing edition is NOT read as one until you also pass `author` — «صحيح البخاري ت البغا» alone is refused, «صحيح البخاري ت البغا» + author «البخاري» resolves. The title must be a PREFIX of the entry's own: «شرح صحيح البخاري», «المدخل إلى صحيح البخاري» and «عمدة القاري شرح صحيح البخاري» contain the work's name and none IS the work. A commentary is rejected (listed in rejected[]): quoting it as the work would attribute its author's words to al-Bukhari. Example: {title:'المغني', author:'ابن قدامة'}. (kind=work only.) | |
| author | No | The author as cited, when known. This is a FILTER, not a hint: a candidate whose author cannot be reconciled with it is rejected rather than ranked down, because that is exactly how a commentary gets returned as the work it comments on. (kind=work only.) | |
| offset | No | Number of results to skip for pagination. Use with `limit` to page through large result sets. The response includes `has_more` and `next_offset` to drive paging. Default: 0. (kind=book|heading|author|period only.) | |
| died_to | No | Hijri year, inclusive UPPER bound on the MAIN AUTHOR's death year (author.death_number). Pair with died_from. (kind=period only.) | |
| edition | No | A specific printing, as the catalogue names it: 'ط السلطانية', 'ت البغا', 'ط التأصيل'. If no entry carries it you get status='not_found' with reason='edition_not_found' and the editions that DO exist — never a different book. (kind=work only.) | |
| options | No | [kind=book] morphology / wildcards / sort / relax_when_empty. [kind=heading] morphology / wildcards / sort ('chronological' = earliest author first); headings are matched in folded form only. [kind=author] morphology / wildcards / sort ('relevance' by default; 'chronological' = by Hijri death year, earliest first, undated last), e.g. {query:'الشافعي', options:{wildcards:false}}. preserve_* return OPTION_NOT_SUPPORTED; search_in is ignored (catalogue entries have no body or footnotes; a heading is a single field). Results are ranked by relevance unless sort says otherwise. (kind=book|heading|author only.) | |
| died_from | No | Hijri year, inclusive LOWER bound on the MAIN AUTHOR's death year (author.death_number). A different column from composed_*, but the same number on 98.5% of dated books. Pair with died_to. At least one of composed_from/composed_to/died_from/died_to is required (BAD_ARG); a missing side is open-ended, and undated books drop out under any bound set. E.g. died_from:700, died_to:800 = 8th-century-Hijri authors. A composed-vs-died question («written in the 8th century by authors who died in the 9th») cannot be answered from this data: a near-empty result means the distinction is unavailable, not that no such book exists. (kind=period only.) | |
| category_id | No | Optional: restrict to one category (use shamela_find(kind='category') for IDs). Categories are flat in master.db. Example: {died_from:600, died_to:700, category_id:17}. (kind=period only.) | |
| composed_to | No | Hijri year, inclusive UPPER bound on book.book_date («تاريخ الكتاب»; see composed_from — it is not a composition year). Pair with composed_from. (kind=period only.) | |
| composed_from | No | Hijri year, inclusive LOWER bound on book.book_date — Shamela's «تاريخ الكتاب». NOT an independent composition year: it holds the main author's death year on 98.5% of dated books (8,461/8,587), so pairing it with died_* almost never narrows anything. Pair with composed_to. (kind=period only.) | |
| include_counts | No | If true (default), include book_count for each category; false returns book_count 0. Costs nothing either way — counts are precomputed. downloaded_count is always filled. (kind=category only.) | |
| downloaded_only | No | [kind=category] If true, list only categories with at least one book installed on this server. Useful to see where the installed library is concentrated across the 41 categories. Default: false. [kind=period] If true, restrict to books whose text is installed on this server — the only ones with searchable page content. Default false lists the whole catalogue. (kind=category|period only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). |
Output Schema
| Name | Required | Description |
|---|---|---|
| books | No | [kind=name] Book matches, best first. [kind=period] book_id, book_name, main author + death year, book_date, category, downloaded; sorted by book_id. (kind=name|period only.) |
| match | No | The single entry, when status is 'exact'. (kind=work only.) |
| notes | No | Guidance on using the result. (kind=work only.) |
| query | No | The query as received. (kind=book|heading|author|name only.) |
| title | No | Title as parsed from the request. (kind=work only.) |
| total | No | [kind=category] Categories listed. [kind=period] Books satisfying every bound. (kind=category|period only.) |
| author | No | Author filter applied; null when none. (kind=work only.) |
| filter | No | Echo of the applied constraints. (kind=period only.) |
| offset | No | [kind=book|heading|author] Offset this page started at. [kind=period] Rows skipped before this page. (kind=book|heading|author|period only.) |
| reason | No | When not_found: 'no_title_match', 'author_mismatch' or 'edition_not_found'. (kind=work only.) |
| status | No | 'exact' — use `match`; 'ambiguous' — see `ambiguity`; 'not_found' — read `reason` (and available_editions for an unknown edition). (kind=work only.) |
| authors | No | Author matches, best first. (kind=name only.) |
| edition | No | Edition requested; null when none. (kind=work only.) |
| results | No | [kind=book] Catalogue entries: book_id, book_name, author_name, category, book_date, downloaded (false = text not installed on this server), snippet, matched_in ('bibliography' | 'description' | null). [kind=heading] Matching headings: book_id, book_name, author_name, title_id (pass to shamela_read(unit='section')), title_text, parent_id (enclosing heading, null at top level). [kind=author] Authors: author_id, author_name, death_year (Hijri, null when unknown), book_count, snippet. (kind=book|heading|author only.) |
| book_ids | No | This page's ids, ready for scope.book_ids. (kind=period only.) |
| coverage | No | Hits rolled up by_category and by_century. (kind=book only.) |
| has_more | No | [kind=book|heading|author] True when another page exists; call again with `next_offset`. [kind=period] True when more rows exist past this page. (kind=book|heading|author|period only.) |
| rejected | No | Entries that matched the words but are not the cited work. (kind=work only.) |
| returned | No | [kind=book|heading|author] Rows in `results` on this call. [kind=period] Rows in this response. (kind=book|heading|author|period only.) |
| ambiguity | No | When ambiguous: 'edition' — one work in several printings: search them as one scope, cite one; 'work' — different books that nothing may choose between («المغني»: al-Dhahabi's book of weak narrators and Ibn Qudama's fiqh): the user must choose. (kind=work only.) |
| truncated | No | |
| candidates | No | Entries that carry the requested title. (kind=work only.) |
| categories | No | Categories by id. (kind=category only.) |
| total_hits | No | Every match in scope, not just the rows returned. (kind=book|heading|author only.) |
| next_offset | No | [kind=book|heading|author] Offset of the next page. Absent on the last page. [kind=period] Offset for the next page; present only when has_more is true. (kind=book|heading|author|period only.) |
| rows_dropped | No | |
| no_title_match | No | True when no returned title carries every query word: hits match by some words or by description, not proof the book is held. (kind=book only.) |
| paging_ceiling | No | Deepest offset paging can reach. Present only when the request went past it: narrow the scope instead of paging further. (kind=book|heading|author only.) |
| terms_truncated | No | True when the query had more words than are searched. (kind=book|heading|author only.) |
| downloaded_total | No | Books installed on this server, whole library. (kind=category only.) |
| relaxed_of_terms | No | Word count the relaxed match is measured against. (kind=book only.) |
| normalized_tokens | No | [kind=book|heading|author] The query after Arabic folding, as actually searched. [kind=name] Tokens after Arabic normalisation. (kind=book|heading|author|name only.) |
| relaxed_min_match | No | Set when no entry held every word: hits carry at least this many of `relaxed_of_terms`. (kind=book only.) |
| available_editions | No | When edition_not_found: the printings the catalogue does carry, shaped like candidates. (kind=work only.) |
| no_confident_match | No | Present when nothing reached score 800 (no name carries the whole query): treat the hits as suggestions. (kind=name only.) |
| truncation_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the safe read-only/idempotent profile, and the description goes well past them: per-kind refusal of foreign parameters, pagination-until-has_more-false, EMPTY_SCOPE, the madhab filter's deliberate exclusion of unresolved-school books, 'downloaded:false → another edition ... or catalogue metadata only', and the warning that `name` always answers. These are operational traits an agent cannot infer from readOnlyHint/destructiveHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and the kind list are front-loaded, and the closing 'Instead:' block cleanly consolidates the anti-pattern routes. It is dense and long, but for a 7-mode, 18-parameter tool every bullet carries distinct operational content rather than filler, so the length is largely earned.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-shape explanation is correctly omitted. Given the complexity — 7 modes, nested scope/options, 100% schema coverage — the description still supplies everything an agent needs to pick a mode, know what gets refused, know how to page, and know which sibling handles the adjacent job.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description adds cross-parameter semantics the schema does not: that a parameter belonging to another kind is refused, that book/heading/author/period page with limit/offset, and that scope.category_ids should carry multiple ids when a subject spans shelves. That is meaningful beyond-schema guidance rather than restatement.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a precise verb+resource framing — 'Catalogue lookup — which books, headings, authors and shelves exist, not page text' — that immediately scopes it against the content-searching sibling shamela_search. Each of the seven `kind` values is given its own concrete definition (book→titles/authors/publication lines, heading→chapter titles, etc.), so an agent can differentiate it from shamela_read, shamela_cite and shamela_get_details without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit per-kind routing plus a closing rule that names alternatives by name: page text → shamela_search, a printed page → shamela_cite(mode='printed_page'), one book's headings → shamela_read(unit='toc'). It also states when NOT to use a mode ('name': always answers, so never use it to verify a citation; 'work': refuses rather than guesses). Both the when and the when-not are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_get_briefServer capabilities and search pitfallsARead-onlyIdempotentInspect
Return this server's machine-readable capability handshake: capabilities, numeric limits, retired tool names with their replacements, and traps (ways a result misleads, each with the response field that proves it fired). Call it first from a programmatic client: inputs are strict, so an argument an older build lacks (e.g. shape, response_format:'none') is a hard validation error that fails the whole call, and tools/list cannot reveal argument support — gate each new argument on its capability string. Cache by brief_hash and re-fetch only when it changes. Constants only: needs no library access and does not fail. Example: {} or {response_format:'json'}.
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| traps | No | |
| limits | No | Numeric server limits by name. |
| truncated | No | |
| brief_hash | No | Digest of every other field; re-fetch only when it changes. |
| capabilities | No | Arguments and response fields this build supports; gate new arguments on these. |
| rows_dropped | No | |
| tool_aliases | No | Retired tool names mapped to their replacement and argument changes. |
| server_version | No | This build's version. |
| truncation_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only, idempotent, non-destructive, non-open-world behavior, but the description adds substantial traits they do not cover: it is constants-only, requires no library access, and 'does not fail', versus other tools whose strict input validation fails the whole call. It also discloses the caching contract via brief_hash, which is operationally important and absent from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first clause, followed by usage, caching, and failure semantics in a logical order, and the closing example is compact. It is dense and slightly long for a single-paragraph description, but each sentence carries distinct operational information rather than restating the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not explain return values, and it does not. For a bootstrap tool it covers everything an agent needs: when to call, what it yields, the validation hazard, the caching strategy, and the fact that it cannot fail — nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single enum parameter is fully documented in the schema, so the baseline is 3. The description adds marginal value by giving concrete invocation examples ('{}' or '{response_format:\'json\'}') and by flagging response_format:'none' as a capability-gated argument, which tells the caller why that enum value may be rejected on an older build.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb+resource ('Return this server's machine-readable capability handshake') and enumerates the payload precisely: capabilities, numeric limits, retired tool names with replacements, and traps. This is clearly distinguishable from siblings like shamela_search or shamela_get_details, which operate on library content rather than server metadata.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit directive — 'Call it first from a programmatic client' — and explains the condition that makes it necessary: strict inputs mean an unsupported argument (shape, response_format:'none') is a hard validation error, and tools/list cannot reveal argument support. It also says how to use the result (gate each new argument on its capability string) and when to re-call (only when brief_hash changes).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_get_detailsGet book or author detailsARead-onlyIdempotentInspect
Catalogue record for one book (kind=book, default) or one author (kind=author), installed or not.
book: authors, category, type, printed-edition flag, whether the text is installed here, the scanned printing and the other editions of the same work (same_group). When a reader tool says BOOK_NOT_DOWNLOADED, pick an installed entry from same_group or answer from this record. Read book_date, edition, editor and publisher per their field notes: never supply a missing one.
author: name, Hijri death year (null = unknown or living) and every catalogued book they wrote or co-wrote, each flagged installed or not. Volumes → shamela_read(unit='parts'); a book by title or subject → shamela_find(kind='book'). Errors: BOOK_NOT_FOUND, AUTHOR_NOT_FOUND.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | Selects what the call does: book | author. Default book. | |
| book_id | No | The book id (e.g. 9942). (kind=book only.) | |
| author_id | No | The author id (e.g. 474 for Ibn Qudama, 57 for Ibn Uthaymeen), from shamela_find(kind='name') with type 'author' or a book's authors[]. A catalogue id, not a death year or book id; shamela_find(kind='author') also gives it. (kind=author only.) | |
| include_books | No | If true (default), include every catalogued book by this author, main or co-author, ordered by book_id. False returns name and death year only. (kind=author only.) | |
| include_cover | No | Attach the book's cover image as an MCP image block when Shamela ships one (1,368 of 8,594 books). The picture is a ~310x460 thumbnail of the scanned printing's title page, so it costs roughly 190 image tokens. Set false to keep the reply text-only; `cover.available` still reports whether one exists. Default: true. (kind=book only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). |
Output Schema
| Name | Required | Description |
|---|---|---|
| scan | No | The scanned printing Shamela holds; null when none. (kind=book only.) |
| books | No | The author's books by ascending book_id; empty when include_books is false. (kind=author only.) |
| cover | No | Title-page thumbnail of the scanned printing; null when none. Says nothing about the real binding or whether a scan exists (377 books have a `scan` but no cover): read `scan`. (kind=book only.) |
| notes | No | Caveats, including citation fields the catalogue lacks. (kind=book only.) |
| editor | No | Editor (محقق) from the front matter; null when absent. (kind=book only.) |
| authors | No | Authors, main author first. (kind=book only.) |
| book_id | No | Catalogue book id. (kind=book only.) |
| edition | No | Edition read from the book's front matter; null when absent. Never invent one. (kind=book only.) |
| printed | No | 1 when page numbers follow a printed edition; otherwise Shamela numbers the pages itself. (kind=book only.) |
| category | No | Category name. (kind=book only.) |
| author_id | No | Author id. (kind=author only.) |
| available | No | True when Shamela offers the book for download. (kind=book only.) |
| book_date | No | Shamela «تاريخ الكتاب», Hijri; on 98.5% of dated books the main author's death year, not a composition year: never cite it as one. (kind=book only.) |
| book_name | No | Catalogue title of the book (Arabic). (kind=book only.) |
| book_type | No | Numeric book type. (kind=book only.) |
| pdf_links | No | Raw scan descriptor from the catalogue; prefer `scan`. (kind=book only.) |
| publisher | No | Publisher from the front matter; null when absent. (kind=book only.) |
| sub_books | No | Catalogue ids of books bound inside this one. (kind=book only.) |
| truncated | No | |
| book_count | No | Number of catalogue books (main or co-author). (kind=author only.) |
| death_text | No | Death date as display text. (kind=author only.) |
| death_year | No | Hijri death year; null when unknown or living. (kind=author only.) |
| downloaded | No | True only when the text is installed on this server and has pages. (kind=book only.) |
| same_group | No | Other catalogue entries of the same work (editions, abridgments: Sahih al-Bukhari is 8, five editions and three abridgments). Quotes from two of them are one source. (kind=book only.) |
| author_name | No | Author name. (kind=author only.) |
| category_id | No | Category id (see shamela_find(kind='category')). (kind=book only.) |
| rows_dropped | No | |
| content_status | No | 'readable', 'downloaded_no_pages' or 'not_downloaded'. (kind=book only.) |
| book_type_label | No | Book type in Arabic: printed, manuscript, journal, thesis, electronic or audio. (kind=book only.) |
| publication_date | No | Hijri publication date, DDMMYYYY, from meta_data, when recorded. (kind=book only.) |
| truncation_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent/non-destructive, but the description adds substantial context beyond them: the error codes, the null-means-unknown semantics for death year, the instruction never to supply a missing bibliographic field, cover-image token cost, and the response_format.none capability requirement.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose followed by tight kind-scoped bullets; the routing line and error list are the only additions. Dense but nearly every clause carries information, though the record-field detail leans on the output schema's territory.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present the description needn't re-explain return values, yet it covers the decision context (installed vs not, same_group fallback), failure codes, and field-interpretation caveats. Nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema already documents kind, book_id, author_id, include_books, include_cover and response_format in detail. The description reinforces defaults ('kind=book, default', 'installed or not') but adds little parameter syntax beyond what the schema provides, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Catalogue record for one book ... or one author'), and the kind=book/kind=author bullets enumerate exactly what each mode returns. It distinguishes itself from siblings by noting shamela_read handles volumes and shamela_find handles title/subject lookups.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use guidance: 'When a reader tool says BOOK_NOT_DOWNLOADED, pick an installed entry from same_group or answer from this record.' It also routes two adjacent cases to shamela_read(unit='parts') and shamela_find(kind='book'), and names the two error codes that signal this tool's failure modes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_lookup_hadithFind a hadith or the books that carry itARead-onlyIdempotentInspect
Hadith. mode=search (default): find a hadith by its wording and trace its takhrij — searches the hadith shelves (Sunnah collections, commentaries, takhrij, hadith sciences) in matn and footnotes, reads hadith keys off the matching pages and lists every collection indexing the same hadith. No offset; if the full text matches nothing, one word is dropped and named in relaxed. Takhrij covers only key_index_books, so few rows is not proof of a weak or rare hadith.
mode=sources: every book recording one hadith_key, with its page_id, one row per book in index order.
A downloaded:false book is catalogued but not installed: use another edition (shamela_get_details(kind='book') same_group). Narrator chains → shamela_lookup_rijal(mode='isnad_search'); general text → shamela_search(match='words').
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Selects what the call does: search | sources. Default search. | |
| limit | No | Maximum number of results to return (1-100, default 20). (mode=search only.) | |
| query | No | The hadith text (or a distinctive part of it). AND-combines words across matn + footnotes. Hadith keys come from each matching page's service annotations, takhrij from hadeeth.db. E.g. {query:'إنما الأعمال بالنيات'}. (mode=search only.) | |
| hadith_key | No | Numeric hadith key (the normalized identifier Shamela uses across collections — e.g. 1234). Different collections of the same hadith share this key. Take it from shamela_lookup_hadith(mode='search'), shamela_read(unit='services'), or the `hadeeth_key` of a chain from shamela_lookup_rijal(mode='isnad') / shamela_lookup_rijal(mode='isnad_search') (a string there; pass it as a number). Read from Shamela's pre-built service/hadeeth.db join, for cross-collection research (Bukhari, Muslim, the Sunan and Musnad references of one hadith); read each page with shamela_read(unit='page'). One row per book, in index order; `total` counts all, `returned` only those installed here unless downloaded_only:false. SERVICE_KEY_NOT_FOUND: no book has the key. Example: {hadith_key:1}. (mode=sources only.) | |
| downloaded_only | No | If true (default), only return books whose text is installed on this server. false also lists catalogue-only editions (downloaded:false); `total` counts both either way. (mode=sources only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). | |
| max_pages_scanned | No | How many top text matches (by relevance) to scan for hadith service keys. This is the only result window: `matches` never exceeds it whatever `limit` says, and there is no offset. Default: 20. Raise it for a common wording. Key-bearing pages come first, then `limit` cuts. (mode=search only.) | |
| search_all_categories | No | Search the ENTIRE library instead of the hadith shelves (كتب السنة، شروح الحديث، التخريج، علوم الحديث). Off by default because unscoped ranking buries the collections under works that merely quote the hadith. Turn on to find who CITES a hadith (e.g. in fiqh or tafsir) rather than who NARRATES it. (mode=search only.) |
Output Schema
| Name | Required | Description |
|---|---|---|
| query | No | The query as received. (mode=search only.) |
| total | No | Distinct books carrying the key, installed or not. (mode=sources only.) |
| matches | No | Matching pages, key-bearing first: book_id, book_name, page_id, snippet (often showing the printed takhrij, «رواه البخاري ومسلم»), snippet_source ('matn' | 'footnote'), matched_in, hadith_keys (read from the page's service annotations). (mode=search only.) |
| relaxed | No | Present when the full text matched nothing and one word was dropped. (mode=search only.) |
| results | No | One row per book, in index order, with its first page for the hadith. (mode=sources only.) |
| takhrij | No | Cross-collection takhrij per hadith key. Drawn only from key_index_books, so few rows is not proof of a weak or rare hadith. (mode=search only.) |
| returned | No | Rows in `results` after downloaded_only. (mode=sources only.) |
| searched | No | 'hadith_shelves' (default) or 'whole_library' (search_all_categories). (mode=search only.) |
| truncated | No | |
| hadith_key | No | (mode=sources only.) |
| rows_dropped | No | |
| index_entries | No | Raw index rows behind `total`. (mode=sources only.) |
| pages_scanned | No | Top matches read for hadith keys (<= max_pages_scanned). (mode=search only.) |
| books_searched | No | Books the text search covered: the hadith shelves (كتب السنة، شروح الحديث، التخريج والأطراف، علوم الحديث), 1,957 here. (mode=search only.) |
| key_index_books | No | Books hadeeth.db indexes hadith keys for (ten here); takhrij can only come from these, so a hadith on 1,746 pages can still yield takhrij from ten books. (mode=search only.) |
| total_text_matches | No | Every page matching the text in the searched shelves. (mode=search only.) |
| truncation_message | No | |
| takhrij_from_key_index | No | True when the matched pages carried no hadith key and takhrij came from re-running the query inside the key-indexed books. (mode=search only.) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnly/idempotent/non-destructive annotations already covering the safety profile, the description adds real behavioral depth: no offset, automatic one-word relaxation surfaced in `relaxed`, takhrij limited to key_index_books, SERVICE_KEY_NOT_FOUND semantics, and the downloaded:false catalogue-vs-installed distinction. These are constraints the agent cannot infer from annotations or schema alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the mode distinction and the highest-value caveats (no offset, takhrij scope) before the sibling routing. It is dense and slightly clause-heavy in places, and a few lines overlap with schema text, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, dual-mode, read-only lookup with an output schema present, the description covers what the schema cannot: mode semantics, result-window interaction, known error codes, and edition-availability caveats. Return values are correctly left to the output schema, so nothing an agent needs before calling is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is already 100%, so the baseline is 3, but the description contributes genuine cross-parameter reasoning the schema does not: that max_pages_scanned is 'the only result window' and `matches` never exceeds it regardless of `limit`, and that limit only cuts after key-bearing pages come first. It also explains the response_format='none' budget tradeoff between text and structuredContent.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Find a hadith ... trace its takhrij') and splits the tool's two distinct behaviors (mode=search vs mode=sources) with concrete outputs for each. An agent can distinguish it from shamela_search and shamela_lookup_rijal purely from this text, since the description names those siblings and the boundary conditions that select between them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing guidance: narrator chains go to shamela_lookup_rijal(mode='isnad_search'), general text to shamela_search(match='words'), missing editions to shamela_get_details(kind='book'). It also states when to flip search_all_categories (to find who CITES vs who NARRATES) and when the sparse takhrij result should not be over-interpreted.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_lookup_quranSearch the Quran or get an ayahARead-onlyIdempotentInspect
Qur'an text. mode=search (default): find verses by Arabic words, typed in إملائي spelling or pasted in Uthmani rasm; words ANDed, results in mushaf order (aya_id 1–6236), not relevance. Zero hits usually means a misspelling: drop a word or use options.wildcards.
mode=aya: fetch verses you can already cite, by aya_id OR surah + aya (never both or neither: BAD_ARG); count gives a run that continues across surahs and stops at the last verse. Each verse in three renderings (body = the spelling search matches, amiri for display). AYA_NOT_FOUND names the valid range.
Commentary → shamela_lookup_tafsir; the words inside books → shamela_search(match='words').
| Name | Required | Description | Default |
|---|---|---|---|
| aya | No | Aya number within the surah, 1..N. Pair with `surah`. (mode=aya only.) | |
| mode | No | Selects what the call does: search | aya. Default search. | |
| count | No | How many consecutive verses to return, starting at the one resolved above (1-20, default 1). Use it for a passage — «the last two verses of al-Baqara» is surah=2, aya=285, count=2, and a short surah comes back in one call. The response always reports `surah_ayat`, that surah's total verse count, so you never have to guess how many to ask for. Verses continue across the surah boundary; each carries its own surah/aya. E.g. {surah:112, aya:1, count:4} = all of al-Ikhlas. (mode=aya only.) | |
| limit | No | Maximum number of results to return (1-100, default 20). (mode=search only.) | |
| query | No | Arabic text of a verse or part of one. Matched against all 6,236 verses in BOTH orthographies — the Egyptian إملائي spelling a user types from memory AND the Uthmani rasm that mushaf apps, quran.com and PDFs copy (ٱ, dagger alef, ﴿﴾, full tashkeel are all handled), so paste the verse exactly as you received it. Every word is ANDed. Single-word queries also match prefixed forms (e.g. «الصبر» matches «بالصبر») AND the same word with «ال» stripped («الملك» is also searched as «ملك»/«للملك»), which widens the answer past the word you typed — the response names those forms in `stem_expanded_to`, tags each hit with the `matched_form` it came in on, and reports in `query_form_hits` how many verses match your word itself. Results come back in mushaf order (aya_id), not by relevance. Hafs from Asim text, pre-built aya/ Lucene index. (mode=search only.) | |
| surah | No | Surah number 1..114. Pair with `aya`. E.g. {surah:55, aya:1} = Ar-Rahman 1. (mode=aya only.) | |
| aya_id | No | Cumulative aya id, 1..6236. Mutually exclusive with surah/aya. E.g. 1 = al-Fatiha 1 (the basmala). (mode=aya only.) | |
| offset | No | Number of results to skip for pagination. Use with `limit` to page through large result sets. The response includes `has_more` and `next_offset` to drive paging. Default: 0. (mode=search only.) | |
| options | No | Currently only the `wildcards` flag is honored. The Quranic index ships pre-built and zero-config. `*` stands for any letters, `?` for one: {query:'الرحم*', options:{wildcards:true}} finds 57 verses. (mode=search only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). |
Output Schema
| Name | Required | Description |
|---|---|---|
| aya | No | Verse number within the surah. (mode=aya only.) |
| body | No | Standard Egyptian imla'i spelling, Hafs from Asim — the form text search matches. (mode=aya only.) |
| amiri | No | Uthmani-script rendering (Amiri), for display to the reader. (mode=aya only.) |
| majma | No | KFQPC Mushaf rendering. (mode=aya only.) |
| query | No | The query as received. (mode=search only.) |
| surah | No | Surah number, 1..114. (mode=aya only.) |
| aya_id | No | Cumulative verse id, 1..6236. (mode=aya only.) |
| offset | No | Offset this page started at. (mode=search only.) |
| verses | No | The requested run in order; the top-level fields repeat verses[0]. (mode=aya only.) |
| results | No | Verses in mushaf order: aya_id (1-6236), surah, surah_name, aya, body (full verse), snippet_body (<mark>…</mark> around matches), matched_orthography, matched_form (single-word queries: the searched form the verse came in on; one listed in stem_expanded_to means the stem matched, not your word, e.g. مَٰلِكِ in 1:4 for «الملك»). (mode=search only.) |
| has_more | No | True when another page exists; call again with `next_offset`. (mode=search only.) |
| returned | No | [mode=search] Rows in `results` on this call. [mode=aya] Number of verses in `verses`. |
| truncated | No | |
| surah_ayat | No | Total verses in the first verse's surah, so you can ask for the rest with `count`. (mode=aya only.) |
| surah_name | No | Arabic surah name. (mode=aya only.) |
| total_hits | No | Every match in scope, not just the rows returned. (mode=search only.) |
| next_offset | No | Offset of the next page. Absent on the last page. (mode=search only.) |
| rows_dropped | No | |
| paging_ceiling | No | Deepest offset paging can reach. Present only when the request went past it: narrow the scope instead of paging further. (mode=search only.) |
| query_form_hits | No | Verses matching the word as typed (or its prefixed forms) rather than the stem: «الملك» returns 60 verses, 28 of them this way. (mode=search only.) |
| terms_truncated | No | True when the query had more words than are searched. (mode=search only.) |
| stem_expanded_to | No | Single-word queries: the extra forms searched beyond the word as typed. (mode=search only.) |
| normalized_tokens | No | The query after Arabic folding, as actually searched. (mode=search only.) |
| truncation_message | No | |
| total_hits_complete | No | False when total_hits is a lower bound. (mode=search only.) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a safe read-only, idempotent operation, and the description adds substantial behavior beyond that: results are in mushaf order not relevance, zero hits usually indicate a misspelling, error codes BAD_ARG and AYA_NOT_FOUND are named, `count` continues across surah boundaries, and single-word search expands stems with reports in stem_expanded_to/query_form_hits. This is well past the annotation bar.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Content is front-loaded with the two mode behaviors and organized by mode rather than by parameter, which reads well for a dispatcher-style tool. It is dense and somewhat long, with a few clauses that echo the schema, but nearly every sentence carries routing or failure-handling value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, dual-mode tool with an output schema and nested options, the description covers mode selection, argument constraints, error signals, pagination fields (has_more/next_offset), and sibling routing. Since an output schema exists it is not obliged to document return values, yet the response fields it does mention are accurate and helpful.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
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 every parameter in depth (including mutual exclusivity of aya_id vs surah/aya and the wildcards caveat). The description restates the mode split and the 'never both or neither' constraint but adds little parameter detail the schema lacks, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a precise verb+resource pair for each mode: 'find verses by Arabic words' (search) and 'fetch verses you can already cite ... by aya_id OR surah + aya' (aya). It explicitly distinguishes itself from shamela_lookup_tafsir (commentary) and shamela_search (words inside books), so an agent can route without opening sibling schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use per mode (search for recall, aya for known citations) and names the alternatives with the condition that selects them: 'Commentary → shamela_lookup_tafsir; the words inside books → shamela_search(match=words)'. It even prescribes a fallback when search returns zero hits (drop a word or use wildcards).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_lookup_rijalNarrators and isnadsARead-onlyIdempotentInspect
Hadith narrators and isnad chains, from Shamela's rijal register and isnad index. mode:
narrators (default): a narrator by name → narrator_id, most-documented first, then earliest death year. Names collide: confirm the death year before using an id.
narrator: one dossier by narrator_id — lineage, death year, tabaqa, Ibn Hajar's and al-Dhahabi's grades, critics' jarh wa-ta'dil verdicts verbatim with source (the only paged part), hadith_notes on audition and irsal; include_network adds isnad-index counts per book and top teachers/students. Quote verdicts as worded; never synthesize a grade.
isnad_search: chains by the narrators in them —
contains(anywhere) ortransmission[teacher_id, student_id] pairs that must be adjacent (direct audition, the stronger test) — each hit with book, page, hadeeth_key and the chain.isnad: the chain(s) printed on one page (book_id/page_id from a search hit) with names and death years, plus the same hadith's other routes — one thread or many. Rules: a parameter of another mode is refused. Chains run ascending (Companion first, collector last). Only ten hadith books are isnad-indexed (see scope_book_ids): an empty isnad_search means no such chain in those ten, not in all literature; most pages answer no_isnad_indexed:true with a no_isnad_reason, not an error. Errors: RIJAL_UNAVAILABLE (register not installed), NARRATOR_NOT_FOUND (search the name again), BOOK_NOT_FOUND, PAGE_NOT_FOUND, BOOK_NOT_DOWNLOADED (try shamela_get_details(kind='book') same_group). Instead: book authors → shamela_find(kind='author'); a hadith by its text → shamela_lookup_hadith(mode='search').
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Selects what the call does: narrators | narrator | isnad_search | isnad. Default narrators. | |
| limit | No | [mode=narrators] Maximum narrators to return (1-50, default 10). [mode=narrator] How many CRITICS of al-jarḥ wa-l-taʿdīl to return (1-100, default 10) — the only part of the dossier that is paged. al-Zuhrī has 56 critics and 184 verdicts; they do not fit one response, and `total_critics` says how many there are. (mode=narrators|narrator only.) | |
| query | No | Part of the narrator's name, in Arabic. Matched against the short name, the full lineage, and the register's الشهرة / اللقب / الكنية / النسب — so «الزهري» and «الأعمش» reach the men known by those nisbas even though neither appears in their recorded name. Folding is the same the page search uses, so «شعبه» finds «شعبة» and tashkeel is ignored. Tokens are ANDed and match anywhere, so «شعبة الحجاج» works even though the name reads «شعبة بن الحجاج». Results are ordered by how much al-jarḥ wa-l-taʿdīl the register holds on each man — the most-discussed «الزهري» first — with the earliest death year breaking ties. The register holds 18,989 narrators, died 2–774 AH. Names collide: check death year AND grade before deciding which «محمد بن إسماعيل» you have. E.g. 'شعبة بن الحجاج'. No hits: shorten or respell it. (mode=narrators only.) | |
| top_n | No | How many teachers and how many students to return, most frequent first (1-100, default 15). (mode=narrator only.) | |
| offset | No | [mode=narrators] Narrators to skip, for paging. Common names match in the thousands — «محمد بن» matches 4,271 — so page with this or narrow the query. Default: 0. [mode=narrator] Critics to skip, for paging through the verdicts. Follow `next_offset` until `has_more` is false. Default: 0. [mode=isnad_search] Chains to skip, for paging; follow `next_offset` while `has_more` is true. An offset past `paging_ceiling` returns no rows. Default: 0. (mode=narrators|narrator|isnad_search only.) | |
| book_id | No | Book id from a search hit (e.g. 1681, Sahih al-Bukhari). Chains exist only for the ten isnad-indexed books listed under shamela_lookup_rijal(mode='isnad_search'); other books answer no_isnad_indexed:true. (mode=isnad only.) | |
| page_id | No | Shamela page id within that book (not the printed page number), from the same hit. An id the book lacks is PAGE_NOT_FOUND. (mode=isnad only.) | |
| contains | No | Narrator ids that must ALL appear in the chain, at any position and in any order. Use for «which reports pass through both X and Y». Ids from shamela_lookup_rijal(mode='narrators'). BAD_ARG when contains and transmission are both empty. E.g. {contains:[2779], scope_book_ids:[1681]} = Shu'ba's chains in al-Bukhari. (mode=isnad_search only.) | |
| max_results | No | Chains to return per page (1-100, default 20). Chains come in index order. (mode=isnad_search only.) | |
| narrator_id | No | The narrator id, as returned by shamela_lookup_rijal(mode='narrators') or inside a chain from shamela_lookup_rijal(mode='isnad'). Example: {narrator_id:4677}. (mode=narrator only.) | |
| max_variants | No | Cap on returned variant routes (1-200, default 20). `variants.truncated` reports when more exist. (mode=isnad only.) | |
| transmission | No | Pairs [teacher_id, student_id] that must appear ADJACENT and in that order — direct transmission, the student having heard from the teacher with nobody in between. This is the question «did X really narrate from Y», and it is strictly stronger than listing both in `contains`. All pairs are ANDed. E.g. [[1580,2779]] = Shu'ba heard from al-Hakam b. Utayba; [[4677,4494]] = Umar to Alqama (20 chains). (mode=isnad_search only.) | |
| scope_book_ids | No | Restrict to these books. The isnād index covers only ten: صحيح البخاري (1681), صحيح مسلم (711), سنن أبي داود (654), سنن الترمذي (7895), سنن النسائي (829), موطأ مالك (28107), مسند الطيالسي (1456), المنتقى لابن الجارود (627 و13071), وعلل الترمذي (642). 45,220 chains in all. (mode=isnad_search only.) | |
| include_network | No | Include the transmission network computed from the isnād index: how many chains this narrator carries, in which books, and their most frequent teachers and students. Set false to skip it when you only need the biography. Default: true. (mode=narrator only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). | |
| include_variants | No | Also return the other routes (طرق) of the same ḥadīth from the other indexed books, matched on Shamela's ḥadīth key. This is what shows whether a report rests on one thread or many. Default: true. (mode=isnad only.) |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | No | (mode=narrator only.) |
| note | No | (mode=narrator only.) |
| query | No | (mode=narrators only.) |
| chains | No | Chains printed on this page. (mode=isnad only.) |
| offset | No | Rows skipped before this page. (mode=narrators|narrator|isnad_search only.) |
| tabaqa | No | Generation, per Taqrib al-Tahdhib. (mode=narrator only.) |
| book_id | No | (mode=isnad only.) |
| network | No | Isnad-index network; null when include_network is false. (mode=narrator only.) |
| page_id | No | (mode=isnad only.) |
| results | No | [mode=narrators] Most-documented narrator first, earliest death year breaking ties. [mode=isnad_search] Chains in index order. (mode=narrators|isnad_search only.) |
| summary | No | kunya, nasab, cities, relations — whatever the register holds. (mode=narrator only.) |
| contains | No | (mode=isnad_search only.) |
| has_more | No | True when more rows exist past this page. (mode=narrators|narrator|isnad_search only.) |
| returned | No | Rows in this response. (mode=narrators|narrator|isnad_search only.) |
| variants | No | Other routes of the same hadith, following its key outward: the route count shows one thread (gharib, غريب) or many (mashhur, مشهور). Null when none or not requested. (mode=isnad only.) |
| full_name | No | (mode=narrator only.) |
| truncated | No | |
| death_year | No | (mode=narrator only.) |
| jarh_tadil | No | This page of critics' verdicts, grouped by critic, each verbatim with book and volume/page (e.g. «تهذيب التهذيب (1/ 101)»). 15,160 of the 18,989 narrators carry verdicts, from 2,821 named critics. (mode=narrator only.) |
| total_hits | No | Chains matching, before paging. (mode=isnad_search only.) |
| narrator_id | No | (mode=narrator only.) |
| next_offset | No | Offset for the next page; present only when has_more is true. (mode=narrators|narrator|isnad_search only.) |
| hadeeth_keys | No | (mode=isnad only.) |
| hadith_notes | No | Fawa'id on audition, irsal and implicit tawthiq: the evidence for whether a chain is connected. (mode=narrator only.) |
| rows_dropped | No | |
| transmission | No | (mode=isnad_search only.) |
| grade_dhahabi | No | (mode=narrator only.) |
| total_critics | No | (mode=narrator only.) |
| total_matches | No | (mode=narrators only.) |
| paging_ceiling | No | Present when offset passed the deepest reachable row. (mode=isnad_search only.) |
| total_verdicts | No | (mode=narrator only.) |
| grade_ibn_hajar | No | (mode=narrator only.) |
| no_isnad_reason | No | no_marker_on_page (the page's own service annotations carry no isnad marker) | marked_but_unindexed | null. (mode=isnad only.) |
| chains_truncated | No | (mode=isnad only.) |
| no_isnad_indexed | No | (mode=isnad only.) |
| page_isnad_markers | No | (mode=isnad only.) |
| truncation_message | No | |
| total_chains_on_page | No | (mode=isnad only.) |
| absent_from_isnad_index | No | True when no indexed chain names this narrator; null when not computed. (mode=narrator only.) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false, and openWorldHint=false, but the description adds substantial context: specific error codes (RIJAL_UNAVAILABLE, NARRATOR_NOT_FOUND, etc.), paging behavior, the fact that empty isnad_search results are not errors but a scope limitation, and a strong quality directive ('Quote verdicts as worded; never synthesize a grade'). This goes well beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but it is well-structured with clear mode bullets and rules. For a 16-parameter, 4-mode tool, the length is mostly justified, and the purpose is front-loaded. A few sentences could be tightened, but it largely earns its space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the description covers the essential context: mode distinctions, scope limits (only ten books indexed), error handling, paging, and alternatives. An output schema exists, so return values need not be explained, and annotations cover safety. The description is complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description reinforces mode behavior and parameter interactions (e.g., contains vs. transmission, paging ceiling), but the schema itself already provides detailed, example-rich descriptions for every parameter. The description adds little new semantic detail for individual parameters beyond what is in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Hadith narrators and isnad chains, from Shamela's rijal register and isnad index,' naming a specific resource and scope. It explicitly distinguishes itself from siblings: 'Instead: book authors → shamela_find(kind='author'); a hadith by its text → shamela_lookup_hadith(mode='search').' An agent can immediately tell what this tool does and what it does not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Each mode is given explicit when-to-use guidance, including conditions and expected inputs ('narrators (default): a narrator by name → narrator_id...', 'narrator: one dossier by narrator_id...'). It names alternatives for adjacent tasks and states a key rule: 'a parameter of another mode is refused.' Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_lookup_tafsirTafsir coverage and texts for an ayahARead-onlyIdempotentInspect
Tafsir on one verse (aya_id OR surah + aya, else BAD_ARG). mode=coverage (default): which tafsir books cover it, fetching no text — shelves 3 (tafsir) and 4 (Qur'anic sciences; not 5, tajwid and qira'at) crossed with Shamela's curated tafsir index, plus index hits from other shelves (in_tafsir_categories:false). Status per book: indexed_covers (with page_id), indexed_no_entry_for_this_aya, or not_indexed_coverage_unknown — NOT evidence the book is silent.
mode=texts: the commentary from several books in one call, each attributed (book, author, death year, printed page), read only from pages the index maps to the verse, never a text-search guess. Each source's note names the next call when its text continues. Example: {surah:2, aya:255, book_ids:[1503, 639]}.
| Name | Required | Description | Default |
|---|---|---|---|
| aya | No | Verse number within the surah, 1..N; requires `surah`. | |
| mode | No | Selects what the call does: coverage | texts. Default coverage. | |
| surah | No | Surah number 1..114; requires `aya`. Alternative to aya_id. | |
| aya_id | No | Cumulative verse id, 1..6236 (e.g. 262 = 2:255). Give this OR surah + aya, not both; a reference that disagrees with surah/aya is BAD_ARG. | |
| book_ids | No | Restrict to these tafsir books, read in the order given (omit it and the installed indexed books are read earliest author first). Books not present in the curated index for this aya are reported with an explicit status instead of text. Use shamela_lookup_tafsir(mode='coverage') to see which books the index covers. (mode=texts only.) | |
| max_sources | No | Maximum number of sources to fetch text for (1-10, default 5). The response-size budget can stop earlier; `remaining_book_ids` lists the sources not read, to pass as book_ids next. (mode=texts only.) | |
| downloaded_only | No | If true (default), list only books whose text is installed on this server. false also lists books the curated index maps to this aya whose text is not installed (downloaded:false) — still useful as catalogue references. (mode=coverage only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). |
Output Schema
| Name | Required | Description |
|---|---|---|
| aya | No | |
| note | No | Caveat: the index is curated, so unknown status is not absence. |
| books | No | Every tafsir-shelf book plus index hits, ordered by status, installed first, then book_id; a long list is cut (rows_dropped). (mode=coverage only.) |
| surah | No | |
| total | No | Distinct books the index maps to this verse, installed or not. (mode=coverage only.) |
| aya_id | No | Cumulative verse id, 1..6236. |
| totals | No | Count of books in each coverage status. (mode=coverage only.) |
| fetched | No | Sources whose text was read. (mode=texts only.) |
| results | No | The index hits alone, repeating books[] rows; filtered by downloaded_only (false adds hits whose text is not installed, downloaded:false). (mode=coverage only.) |
| sources | No | Read only from pages the curated service/tafseer.db maps to this verse; there is no text-search fallback, which misattributes verses through shared phrases and the basmala. (mode=texts only.) |
| _display | No | (mode=texts only.) |
| returned | No | Rows in `results`. (mode=coverage only.) |
| truncated | No | |
| surah_name | No | |
| rows_dropped | No | |
| coverage_note | No | (mode=coverage only.) |
| index_entries | No | Raw index rows; exceeds `total` when commentary spans pages. (mode=coverage only.) |
| total_indexed | No | Books the curated index maps to this verse. (mode=texts only.) |
| remaining_book_ids | No | Indexed sources not read in this call; pass as book_ids to continue. (mode=texts only.) |
| truncation_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Even with annotations already declaring readOnly/idempotent/non-destructive, the description adds substantial behavioral context: the exact status values returned (indexed_covers, indexed_no_entry_for_this_aya, not_indexed_coverage_unknown) and the warning that these are NOT evidence a book is silent; that text is read only from index-mapped pages, never a search guess; and that `note`/`remaining_book_ids` drive the next call. This is well beyond what the annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and the mode-by-mode organization is logical, with a concrete example closing it out. The coverage-mode sentence is a long run-on dense with parentheticals, so it is not maximally scannable, but nearly every clause carries actionable information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter, dual-mode tool with an output schema, the description covers the mode semantics, status vocabulary, pagination/continuation via remaining_book_ids, and where the structured output lives. Nothing an agent needs to invoke it correctly is missing, and return-value detail is rightly left to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds cross-parameter meaning: the aya_id vs surah+aya exclusivity with a BAD_ARG outcome, the semantics of book_ids ordering and non-indexed books being reported as status, and the response_format character-budget tradeoff. This goes past restating field docs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a concrete verb+resource ('Tafsir on one verse') and immediately disambiguates the two operating modes (coverage vs texts). It also implicitly separates itself from siblings like shamela_lookup_quran and shamela_lookup_hadith by naming the resource and the coverage/text distinction. An agent can tell what this does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly describes when to pick each mode — coverage to discover which books cover the verse, texts to pull attributed commentary — and the schema reinforces this ('Use shamela_lookup_tafsir(mode="coverage") to see which books the index covers'). It does not state when to prefer a sibling lookup tool instead, so the routing guidance is strong but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_readRead pages, sections and tables of contentsARead-onlyIdempotentInspect
Read an installed book's text and structure by internal ids. unit:
page (default): one page_id → body (author's matn), foot (editor's footnotes), printed page label, prev/next page ids, enclosing headings.
range: up to 20 consecutive pages from start_page_id, each with text, footnotes, printed page — to read on past a hit or through a span.
section: one chapter by title_id with its sub-headings, up to the next heading outside it.
toc: headings with their title_ids; top level by default, parent_id/depth expand, containing_page_id gives the chain enclosing a page.
parts: volumes — part label, page count, first/last page_id.
services: what one page cites (aya ids, hadith keys, isnad markers, as stored) → shamela_lookup_quran(mode='aya'), shamela_lookup_hadith(mode='sources'), shamela_lookup_rijal(mode='isnad'). Rules: a parameter of another unit is refused. page_id is not the printed page and ids have gaps: step with prev_page_id/next_page_id, not ±1; for a printed «vol./page» call shamela_cite(mode='printed_page') first. A size budget cuts long text: follow body_has_more (body_part+1) or next_start_page_id. Errors: PAGE_NOT_FOUND (also a range start past the end), TITLE_NOT_FOUND, BOOK_NOT_FOUND, BOOK_NOT_DOWNLOADED (catalogued, not installed: use an installed edition from shamela_get_details(kind='book') same_group). Instead: a heading by its words → shamela_find(kind='heading'); books of untitled «فصل» headings → shamela_search(match='words') scoped to the book; any catalogued book's metadata → shamela_get_details(kind='book').
| Name | Required | Description | Default |
|---|---|---|---|
| unit | No | Selects what the call does: page | range | section | toc | parts | services. Default page. | |
| count | No | How many consecutive pages to fetch (1–20, default 5). Fewer come back when the ~12,000-character budget is reached; has_more then stays true. Use shamela_read(unit='section') for full chapter reads. Faster than looping unit='page'. E.g. {unit:'range', book_id, start_page_id:1, count:5}. (unit=range only.) | |
| depth | No | Levels below parent_id to include (1–5, default 1); deeper levels arrive nested in `children`. Ignored when containing_page_id is set. E.g. {unit:'toc', book_id, depth:1} lists the top-level chapters. (unit=toc only.) | |
| book_id | No | The book id, from shamela_find(kind='book'), shamela_find(kind='work') or shamela_find(kind='name'). Installed ids: shamela_list_downloaded_books. | |
| page_id | No | [unit=page] Internal page id, as search hits, shamela_read(unit='toc') and shamela_cite(mode='printed_page') return it; not the printed page number. Ids have gaps, so take neighbours from prev_page_id/next_page_id. [unit=services] Shamela's internal page id (from a search hit or reader tool), not the printed page number. Example: {unit:'services', book_id:1681, page_id:10}. (unit=page|services only.) | |
| title_id | No | The title id of the chapter / section to fetch, from shamela_read(unit='toc') or shamela_find(kind='heading'). Its sub-headings are included. (unit=section only.) | |
| body_part | No | For long pages: when the body exceeds ~4000 characters it is split into parts. Pass the 1-based part to read (default 1). The response reports body_part/body_total_parts/body_has_more; request the next part by incrementing. The footnote/comment are returned with part 1. (unit=page only.) | |
| keep_html | No | [unit=page] If true, preserve inline HTML markers (e.g. <span data-type='title'>). Default false strips them for plain Arabic display. [unit=range|section] If true, keep Shamela's inline markup: <span data-type='title'> headings, <a href="inr://man-<narrator_id>"> narrator links, <hadeeth-N> markers. Default false strips them for plain Arabic display. (unit=page|range|section only.) | |
| max_pages | No | Cap on pages to read (1–100, default 30). The ~12,000-character budget can stop the read earlier; either way truncated:true and next_start_page_id say where to resume with shamela_read(unit='range'). (unit=section only.) | |
| parent_id | No | Title id whose children to list; 0 (default) = top-level chapters. Ignored when containing_page_id is set. (unit=toc only.) | |
| start_page_id | No | First page id to read (inclusive). To continue a range that was cut short, pass the previous response's next_start_page_id. (unit=range only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). | |
| containing_page_id | No | Page id. Switches to ancestor-chain mode: returns the headings that enclose this page, root to leaf, in `ancestor_chain`; parent_id and depth are then ignored. E.g. containing_page_id:17 gives the chapter holding page 17. (unit=toc only.) |
Output Schema
| Name | Required | Description |
|---|---|---|
| raw | No | The raw service record, for debugging. (unit=services only.) |
| ayat | No | Cumulative aya ids (1-6236, 262 = 2:255) cited on the page, as stored; pass to shamela_lookup_quran(mode='aya'). (unit=services only.) |
| body | No | Main text (matn), or the requested body_part of it. (unit=page only.) |
| foot | No | Footnotes (editor's words, not the author's); returned with body_part 1 only. (unit=page only.) |
| mode | No | 'subtree' (parent_id/depth) or 'ancestor_chain' (containing_page_id). (unit=toc only.) |
| part | No | Volume/part label, e.g. '4'; null for single-volume books. (unit=page only.) |
| count | No | Pages actually returned (may be fewer than requested). (unit=range only.) |
| depth | No | Levels expanded in subtree mode; null in ancestor_chain mode. (unit=toc only.) |
| esnad | No | Raw isnad markers, one string per chain: «<zero-padded hadith key> s <narrator ids, Companion first, collector last>». Ids, not names; resolve with shamela_lookup_rijal(mode='isnad'). (unit=services only.) |
| pages | No | Pages in reading order. (unit=range|section only.) |
| parts | No | Volumes in reading order: whether a citation needs a part designator. Empty for a single-volume book unless its pages carry one part label (kept: citations print it). (unit=parts only.) |
| titles | No | Subtree mode: the headings, nested via children. Empty under a leaf. (unit=toc only.) |
| book_id | No | Catalogue book id. |
| comment | No | User annotation; returned with body_part 1 only. (unit=page only.) |
| hadeeth | No | Numeric hadith keys, as stored; pass to shamela_lookup_hadith(mode='sources'). (unit=services only.) |
| page_id | No | [unit=page] Internal page id that was read. [unit=services] Page id. (unit=page|services only.) |
| _display | No | Advice on presenting a long text (show in parts, or ask the user how); null when the text is short. (unit=page|range|section only.) |
| has_more | No | True when pages exist after the last one returned. (unit=range only.) |
| title_id | No | Heading that was read. (unit=section only.) |
| body_part | No | 1-based part of the body returned. (unit=page only.) |
| book_name | No | Catalogue title of the book (Arabic). (unit=page|range|section|toc|parts only.) |
| parent_id | No | Parent expanded in subtree mode; null in ancestor_chain mode. (unit=toc only.) |
| truncated | No | True when fewer pages were returned than the section has. |
| title_text | No | Heading text. (unit=section only.) |
| author_name | No | Main author name. (unit=page|range|section only.) |
| end_page_id | No | Last page id of the section. (unit=section only.) |
| esnad_count | No | Number of isnad markers. (unit=services only.) |
| total_pages | No | Page records in the book. (unit=parts only.) |
| has_services | No | False when the page carries no markers (common outside hadith works). (unit=services only.) |
| next_page_id | No | Next existing page id; null at the end. (unit=page only.) |
| prev_page_id | No | Previous existing page id (ids have gaps); null at the start. (unit=page only.) |
| printed_page | No | Printed page label as Shamela renders it, e.g. '4/ 405'; null when the page has no printed number. (unit=page only.) |
| rows_dropped | No | |
| body_has_more | No | True when another body_part follows. (unit=page only.) |
| category_path | No | Category names, broadest first. (unit=page only.) |
| start_page_id | No | [unit=range] First page id requested. [unit=section] First page id of the section. (unit=range|section only.) |
| ancestor_chain | No | ancestor_chain mode: headings enclosing the page, root to leaf. (unit=toc only.) |
| is_multi_volume | No | True when the pages carry more than one part label. (unit=parts only.) |
| body_total_parts | No | How many parts the body is split into. (unit=page only.) |
| containing_titles | No | Chapter headings enclosing the page, root to leaf. (unit=page only.) |
| next_start_page_id | No | [unit=range] Where to continue when the size budget cut the range short; null otherwise. [unit=section] Continue with shamela_read(unit='range') from here; null when the section is complete. (unit=range|section only.) |
| truncation_message | No | |
| total_pages_in_section | No | Pages the whole section spans. (unit=section only.) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the read-only/safe profile; the description goes well beyond them with a size-budget model (~12,000 chars, body_has_more/body_part+1, next_start_page_id), truncation flags, the fact that page ids have gaps so ±1 stepping is wrong, and a named error taxonomy (PAGE_NOT_FOUND, TITLE_NOT_FOUND, BOOK_NOT_FOUND, BOOK_NOT_DOWNLOADED with remediation). This is exactly the operational context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the overview and the unit list, then rules, then errors, then alternatives — a deliberate and correct ordering. Despite its length, almost every clause carries load (mode behavior, budget, id semantics, error recovery), and the dash-per-unit format is scannable rather than prose-bloated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 13-parameter, six-mode dispatcher with an output schema, the description covers everything an agent needs: which unit to pick, which parameters belong to which unit, continuation on truncation, id semantics, and recoverable errors. Return-value shape is delegated appropriately to structuredContent and the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the per-parameter unit scoping is largely already in the schema. The description still adds cross-parameter semantics the schema cannot express: 'a parameter of another unit is refused', the continuation contract (feed next_start_page_id back in), and the budget interaction between range and section reads. That is real added meaning, though it does not restate every parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Starts with a specific verb+resource ('Read an installed book's text and structure by internal ids') and then enumerates the six distinct modes, each with what it returns (page → body/foot/printed label/prev-next ids; toc → headings with title_ids; parts → volumes). The closing 'Instead:' block names sibling tools and the conditions that route away from this one, so an agent can distinguish it from shamela_find, shamela_search and shamela_get_details without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use guidance per mode ('to read on past a hit or through a span', 'for a printed «vol./page» call shamela_cite first') plus negative routing: headings by words → shamela_find(kind='heading'), untitled «فصل» headings → shamela_search(match='words'), metadata → shamela_get_details. It also states a hard rule about what will be refused, which is the kind of exclusion guidance that prevents wrong calls.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_searchSearch page text (words, phrase, exact, boolean, batch)ARead-onlyIdempotentInspect
Full-text search inside the pages (matn and footnotes) of installed books. match picks how the query is read:
words (default): every word required, ranked by relevance; options add morphology, wildcards, chronological sort. An all-words miss retries with fewer words (relaxed_min_match).
phrase: the words consecutively (a quotation). near: all words within
distance, any order. Both verified in the full page text.exact: diacritics, hamza/alef forms or digit systems kept distinct («أحمد» not «احمد», «عِلْم» not «عَلَم», ٢٥٥ not 255); set at least one
preserveflag.boolean: every all_of term, one or more any_of, no none_of (الوقف with المسجد or المقبرة, without البيع); one query over the whole index, so total_hits is exact and exclusion exhaustive.
batch: 1–24 scoped
queriesrun at once, merged and deduped by page (probe_ids); no paging, cut at max_total_passages. Rules: a parameter of another match value is refused. Page with limit/offset until has_more is false. scope.madhab drops books of unknown school: omit it for comparative questions; set scope.citable_only before quoting a page number. Follow-up rounds: exclude_pages / exclude_work_group_ids keep out pages already used and other printings of the same work. EMPTY_SCOPE: the scope matched no book. Instead: chapter headings → shamela_find(kind='heading'); titles → shamela_find(kind='book'); verses → shamela_lookup_quran(mode='search'); a hadith's wording → shamela_lookup_hadith(mode='search'). Example: {query:'استصناع', scope:{category_ids:[17]}}.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of results to return (1-100, default 20). (match=words|phrase|near|exact|boolean only.) | |
| match | No | Selects what the call does: words | phrase | near | exact | boolean | batch. Default words. | |
| query | No | [match=words] Arabic words, ANDed; each may match in body or footnotes, e.g. {query:'الكلام'}. A word the library lacks in your spelling is searched in the spelling the books use and reported in `respelled_terms`: say so when you quote. [match=phrase] The words as a consecutive phrase, e.g. {query:'خيار المجلس'}. [match=near] The words within `distance` of each other, in any order. Phrase and near candidates come from an AND search and are verified in the full page text up to 1,500 pages or 12 s, so `total_verified` is not a library total; narrow `scope` when `candidate_cap_hit`. [match=exact] The exact string, typed WITH the diacritics / hamza form / digit system to enforce (it is not auto-diacritized) and matched as written; `preserve` decides which distinctions count. An AND search gathers at most 100 candidate pages and each is checked against the book's raw text; results keep candidate-relevance order. (match=words|phrase|near|exact only.) | |
| scope | No | Restrict to books, authors, categories, a Hijri period or the other filters below; get ids from shamela_find(kind='category') or shamela_find(kind='name'). Strongly recommended on common words for match=phrase|near (verification stops after 1,500 candidate pages or 12 s) and match=exact (at most 100 candidate pages are verified): a narrow scope is what lets that window cover the topic. match=boolean: an unscoped search over a large library is exhaustive but slow, so scope narrows the question and speeds it up. (match=words|phrase|near|exact|boolean only.) | |
| shape | No | How much of each hit to return. 'full' (default): every field, snippets included — ask for it when the answer will QUOTE the page. 'brief': book_id/page_id, printed_page, match_quality and matched_in_section, book metadata hoisted into a top-level `books` keyed by book_id, NO snippet — which pages, how well each matched and how to cite them, for a fraction of the characters, so far more rows survive the budget. 'index': book_id/page_id only, to choose what to read before paying to read it. Requires the 'shape.full_brief_index' capability (see shamela_get_brief). (match=words|phrase|near|batch only.) | |
| all_of | No | The three lists are ONE Lucene BooleanQuery over the whole index: all_of MUST, any_of SHOULD (at least one), none_of MUST_NOT. AND — terms that must ALL appear on the page; a multi-word term is itself AND-searched (its words co-occur; not a phrase). Leave empty to rely on any_of, but not both: BAD_ARG. Results are ranked by relevance. E.g. {match:'boolean', all_of:['الوقف'], any_of:['المسجد','المقبرة'], none_of:['البيع'], scope:{category_ids:[17]}}. (match=boolean only.) | |
| any_of | No | OR — at least ONE of these terms must appear on the page. Union of every term's hit set, then intersected with the all_of result. Leave empty to rely on all_of. (match=boolean only.) | |
| offset | No | Number of results to skip for pagination. Use with `limit` to page through large result sets. The response includes `has_more` and `next_offset` to drive paging. Default: 0. (match=words|phrase|near|exact|boolean only.) | |
| none_of | No | NOT — pages containing ANY of these terms are excluded, across the whole index (a MUST_NOT clause, not a subtraction inside a sampled window). Optional. (match=boolean only.) | |
| options | No | Search options: morphology, wildcards, sort, search_in (body/foot), relax_when_empty. Defaults to body+foot, no toggles. preserve_* redirect to shamela_search(match='exact'). E.g. {query:'كلم', options:{morphology:true}}. (match=words only.) | |
| queries | No | Several wordings of one question, run concurrently to assemble its evidence; results are merged, deduped by (book_id, page_id) and attributed to the probes that found each page (`probe_ids`): a page several probes found is corroboration across wordings, not a duplicate. Every probe's scope must carry book_ids, author_ids, category_ids or madhab, else the whole call is BAD_ARG. A probe that errors or outlasts deadline_ms is reported in its own slot and sets `incomplete`: a thin result is then not the library being silent. E.g. {queries:[{query:'الوتر واجب', scope:{category_ids:[14,19]}}, {query:'حكم صلاة الوتر', mode:'near', scope:{madhab:['hanafi']}}]}. (match=batch only.) | |
| distance | No | For match='near': maximum word span from the FIRST to the LAST query word, counted inclusively — 1 = adjacent, 2 allows one word between two query words. Ignored for match='phrase'. Suits fiqh terms that sit close but not adjacent: {match:'near', query:'بيع قبض', distance:5, scope:{category_ids:[17]}}. Default: 5. (match=phrase|near only.) | |
| preserve | No | Which distinctions to enforce when each candidate is verified; at least one must be true (none = BAD_ARG), and every unset feature folds. E.g. {query:'أحمد', preserve:{preserve_hamza:true}}, {query:'عِلْم', preserve:{preserve_diacritics:true}}. (match=exact only.) | |
| search_in | No | [match=phrase|near] Which page sections to verify the phrase in: body (matn), foot (footnotes). Default both; a hit's `matched_in_section` says where it was found. [match=boolean] Which page sections every clause (all_of, any_of and none_of alike) looks in: body (matn), foot (footnotes). Default ['body','foot']. (match=phrase|near|boolean only.) | |
| deadline_ms | No | Wall-clock budget for the whole batch. Probes still running when it expires are reported with status='timeout' and contribute nothing. A timeout is NOT a negative finding — it means the question was not fully asked. Default: 8000. (match=batch only.) | |
| exclude_pages | No | Exact pages to keep out — the pages a previous round already returned. Excluding these rather than whole books is what lets a follow-up search find MORE evidence in a book that has already contributed some. (match=words|phrase|near only.) | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). | |
| exclude_book_ids | No | Book ids to keep out of the results entirely. (match=words|phrase|near only.) | |
| exclude_author_ids | No | Exclude every book by these authors. (match=words|phrase|near only.) | |
| max_total_passages | No | Hard cap on merged rows returned. Rows are ordered by match quality then probe agreement before the cut, so the cap drops the weakest evidence rather than an arbitrary tail. `truncated` says whether it fired. Default: 60. (match=batch only.) | |
| exclude_category_ids | No | Exclude every book on these shelves. (match=words|phrase|near only.) | |
| exclude_work_group_ids | No | Exclude every catalogue entry of these works — all printings at once. This is the one to use after a round returned «صحيح البخاري - ط السلطانية»: excluding that book_id alone leaves the other seven entries of group 1681 free to return the same text again as if it were a second source. (match=words|phrase|near only.) |
Output Schema
| Name | Required | Description |
|---|---|---|
| mode | No | 'phrase' or 'near', as searched. (match=phrase|near only.) |
| books | No | shape 'brief' only: book metadata keyed by book_id, hoisted off the rows. (match=words|phrase|near|batch only.) |
| notes | No | Caveats about how the expression was evaluated. (match=boolean only.) |
| query | No | The query as received. (match=words|phrase|near|exact only.) |
| all_of | No | AND terms, as searched. (match=boolean only.) |
| any_of | No | OR terms, as searched. (match=boolean only.) |
| offset | No | Offset this page started at. (match=words|phrase|near|exact|boolean only.) |
| probes | No | One report per probe, in request order. (match=batch only.) |
| by_book | No | Returned rows per book name. (match=batch only.) |
| none_of | No | NOT terms, as searched. (match=boolean only.) |
| results | No | [match=words|phrase|near] Matching pages. shape 'full': book_id, book_name, author_name, category, book_date, work_group_id, madhab fields, page_id, printed_page, matched_in, match_quality ('exact_phrase' | 'near' | 'all_terms' | 'relaxed': a near miss is not a located quotation), matched_in_section ('body' | 'footnote' | 'both'; 'footnote' = the editor's voice, not the author's), snippet_body/snippet_foot (<mark> around matches). shape 'brief' drops book metadata into `books`; 'index' keeps ids only. [match=exact] Verified pages: book_id, book_name, author_name, category, book_date, page_id, printed_page, matched_in (sections holding the exact form), snippet. [match=boolean] Matching pages: book_id, book_name, author_name, category, book_date, madhab fields, page_id, printed_page, matched_in, matched_terms, snippet_body, snippet_foot. [match=batch] Merged page rows (as shamela_search(match='words'), per `shape`) plus probe_ids (every probe that found the page), ordered by match_quality then probe agreement. A 'footnote' matched_in_section is the editor's voice. |
| coverage | No | Roll-up of hits by_category and by_century (the whole sample), by_book and by_author (the largest top_n only, so they do not sum to it) and edition_groups (one work under several catalogue entries: one source, not corroboration). A census only when sample_is_complete; otherwise a top-scoring sample of sampled_hits. (match=words only.) |
| distance | No | Word span used for mode 'near'. (match=phrase|near only.) |
| has_more | No | True when another page exists; call again with `next_offset`. (match=words|phrase|near|exact|boolean only.) |
| preserve | No | The preserve_* flags enforced on this call. (match=exact only.) |
| returned | No | Rows in `results` on this call. (match=words|phrase|near|exact|boolean only.) |
| exclusion | No | What the `exclude_*` parameters removed. Present only when used. (match=words|phrase|near only.) |
| truncated | No | |
| incomplete | No | True when any probe errored or timed out: a thin result is then not the library being silent. (match=batch only.) |
| total_hits | No | [match=words] Every match in scope, not just the rows returned. [match=boolean] Exact count of pages matching the whole expression. (match=words|boolean only.) |
| next_offset | No | Offset of the next page. Absent on the last page. (match=words|phrase|near|exact|boolean only.) |
| scope_count | No | Books in the resolved scope; -1 when unscoped. (match=words|phrase|near|boolean only.) |
| rows_dropped | No | |
| edition_groups | No | Works present under several catalogue entries in these rows: read each as one source. (match=batch only.) |
| paging_ceiling | No | Deepest offset paging can reach. Present only when the request went past it: narrow the scope instead of paging further. (match=words|boolean only.) |
| total_verified | No | Matches confirmed within the scanned window, not a library total. (match=phrase|near|exact only.) |
| zero_hit_terms | No | Query words with no entry in the library as spelled. A zero then reflects spelling, not the topic. (match=words|phrase|near|exact|boolean only.) |
| respelled_terms | No | {typed, searched_instead, hits}: a word absent as typed was searched in the spelling the books use. (match=words only.) |
| terms_truncated | No | True when the query had more words than are searched. (match=words only.) |
| relaxed_of_terms | No | Word count the relaxed match is measured against. (match=words only.) |
| scope_resolution | No | Requested book_ids split into resolved and `dropped` (not in the catalogue, never searched). (match=words|phrase|near only.) |
| candidate_cap_hit | No | True when the candidate window filled up: more matches may exist outside it; narrow the scope. (match=phrase|near|exact only.) |
| normalized_tokens | No | The query after Arabic folding, as actually searched. (match=words only.) |
| relaxed_min_match | No | Set when no page held every word: hits carry at least this many of `relaxed_of_terms`. (match=words only.) |
| truncation_message | No | |
| morphology_fallback | No | True when the literal search found nothing and was re-run with morphology (root forms). (match=words only.) |
| unattributable_books | No | Books excluded by scope.madhab because no school can be established for them. (match=words|phrase|near only.) |
| total_unique_passages | No | Distinct pages found across all probes, before the max_total_passages cut. (match=batch only.) |
| zero_due_to_exclusion | No | True when pages matched but every one was excluded: not evidence of absence. (match=words|phrase|near only.) |
| morphology_expanded_to | No | options.morphology only: exactly what was searched, per word. Roots are ambiguous and every reading is kept («كتب» also searches تبب/توب/وتب, perdition and repentance), so results are a SUPERSET of the word asked for. (match=words only.) |
| total_candidates_scanned | No | Candidate pages verified against the page text. (match=phrase|near|exact only.) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is low, yet the description adds substantial behavior: relaxed_min_match retry, EMPTY_SCOPE, candidate caps (1,500 pages/12 s for phrase/near, 100 for exact), deadline timeouts framed as 'not a negative finding', respelled_terms, and exclusion semantics. This is well beyond what the annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the resource and a per-mode breakdown, and nearly every sentence carries routing or rule content. It is dense and long, and some match-mode detail overlaps the schema's own parameter text, but on balance the length is earned by the tool's 22-parameter surface.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a highly complex tool (22 params, nested scope, batch mode, enums), the description covers mode selection, scoping, pagination, follow-up exclusions, and error states. An output schema exists, so return-format gaps are not the description's burden.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, establishing a baseline of 3, but the description adds cross-parameter meaning not obvious from the schema alone — e.g. 'a parameter of another match value is refused', the concurrency/merge/dedup behavior of batch probes, and the follow-up-round exclusion strategy. Useful synthesis rather than pure repetition.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — 'Full-text search inside the pages (matn and footnotes) of installed books' — and immediately decomposes the tool by match mode. It explicitly distinguishes itself from siblings (headings → shamela_find, verses → shamela_lookup_quran, hadith → shamela_lookup_hadith), so an agent can route without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use rules per mode (words = every word required, phrase = quotation, exact = typed distinctions, boolean = whole-index exhaustive, batch = 1–24 probes), plus scope guidance (omit madhab for comparative questions, set citable_only before quoting) and a full 'Instead:' routing block. When-not and alternatives are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_search_librarySearch the classical Islamic libraryARead-onlyIdempotentInspect
Search one named shelf of the classical Islamic library (8,594 works) for quotable passages: verbatim Arabic with book, author, printed volume/page, edition and a link to the page in the Quran Gallery Maktabah reader. The default first search for hadith, tafsir, fiqh or creed. Not for isnads, narrators or diacritic-exact wording. Use shamela_search (match "words") to pin books or categories or to page past 10 results, shamela_read (unit "page") to read a whole page. Scope is one shelf per call; call again with another shelf to widen. Ranking: exact phrase first, then all the words; a madhhab scope asks that school's own books first; main text before footnote. relaxedToTokens and note flag a weaker match; no passages means absent from that scope, not from the library. A non-Arabic query or unknown scope returns a tool error naming the fix.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum passages to return (max 10). | |
| query | Yes | Arabic search text. A quoted wording works best; a topic also works. | |
| scope | Yes | hadith-primary — The eight primary hadith collections, edition-pinned; tafsir-canonical — Canonical tafsir — Ibn Kathir, al-Tabari, Ibn al-Jawzi first; fiqh-hanafi — Hanafi fiqh (+ usul, comparative); fiqh-maliki — Maliki fiqh (+ usul, comparative); fiqh-shafii — Shafi'i fiqh (+ usul, comparative); fiqh-hanbali — Hanbali fiqh (+ usul, comparative); fiqh-comparative — All four schools plus comparative and fatwa collections; aqeedah — Creed and sects; hadith-sciences — Hadith commentary, takhrij and the sciences of hadith; tafsir — The whole tafsir shelf and Quranic sciences; seerah — Prophetic biography, history and biographical dictionaries; lugha — Arabic language, lexicons, grammar and adab |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Present only when the result needs a caveat; carry it with the passages. |
| scope | No | The scope searched, as sent. |
| passages | No | Best evidence first: exact phrase before word matches, main text before footnote, the school's own shelf before the wider one. Empty when nothing in the scope matched. |
| totalMatches | No | Matching pages the library verified in the scope before the limit, or null. |
| booksSearched | No | Books in the searched scope, or null when the library did not say. |
| relaxedToTokens | No | True when the exact phrase was not found and a looser word search answered. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this a safe, idempotent, closed-world read, so the description's job is to add operational context, and it does: result ranking order (exact phrase, then all words, madhhab-first for a school scope, main text before footnote), the relaxedToTokens/note weakened-match flag, and the crucial negative-result semantics (no passages means absent from that scope, not the library). It also discloses error behavior for non-Arabic queries and unknown scopes. Not a 5 only because the cap interaction with paging is left to the sibling reference rather than spelled out.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and payload, then usage, then ranking and edge cases — a sensible order with no filler sentences. It is dense and clause-heavy in places (the ranking and madhhab notes are packed into single sentences), which costs a little readability against a genuine 5, but every sentence carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with a 12-value scope enum, a hard limit cap, and a non-obvious negative-result meaning, the description covers the decisions an agent must make: which shelf, when to widen scope, how results are ordered, how to read weak matches, and how errors surface. An output schema exists, so return-shape explanation is optional, yet the passage fields are still summarized helpfully.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema: scope is one shelf per call and must be re-called to widen, and a madhhab scope ranks that school's own books first, which is a ranking behavior the enum text does not state. Query phrasing guidance (quoted wording works best) duplicates the schema slightly rather than extending it, keeping this from a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (search) and scoped resource (one named shelf of the classical Islamic library, 8,594 works) and names the payload returned: verbatim Arabic with book, author, volume/page, edition and a reader link. It explicitly contrasts itself with shamela_search and shamela_read, so an agent can place it among siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use ("the default first search for hadith, tafsir, fiqh or creed"), explicit exclusions (isnads, narrators, diacritic-exact wording), and names the alternatives with the exact condition that selects each: shamela_search with match "words" for pinning books/categories or paging past 10, shamela_read with unit "page" for full pages. The one-shelf-per-call rule plus "call again with another shelf to widen" removes the main usage ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_survey_topicSurvey a topic across the libraryARead-onlyIdempotentInspect
Count how much the library holds on a term and where: the exact matching-page total plus its distribution by category, Hijri century, book and author (top 15 each). Statistics only, never passages — use shamela_search(match='words') instead to retrieve and read the pages. Run it before searching to size a topic and pick scope.category_ids (map by_category names to ids with shamela_find(kind='category')). mode 'literal' (default, 6–9 ms) counts the word as written; 'morphological' counts every derived form of its root (seconds) and is often far broader. coverage_capped:true means the breakdown is a top-5,000 sample whose counts are floors; total_hits stays exact. No match = total_hits 0; EMPTY_SCOPE when scope matches no book. Example: {term:'الاستصناع', scope:{category_ids:[14,15,16,17]}}; {term:'التيمم', scope:{citable_only:true}}.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | 'literal' counts pages carrying the WORD as written (plus the ordinary spelling folds). 'morphological' expands it to every AlKhalil root reading and counts those — which is far broader than most callers expect: «الاستصناع» reports 393,498 pages across 7,405 books morphologically against 1,510 literally, an answer that says every shelf holds the topic. Use 'literal' to size a topic before planning retrieval; use 'morphological' to trace a ROOT through its derivations. | literal |
| term | Yes | Arabic word or root to profile (e.g. «الاستصناع»، «صبر»، «رحم»). Under mode='literal' (default) only the word as written is counted; under mode='morphological' it is matched via the AlKhalil analyzer, so all derived forms (صابر، يصبر، اصطبار…) are counted, not just the literal string. | |
| scope | No | Restrict the profile to specific books, authors, categories, or a Hijri date range. Use shamela_find(kind='category') / shamela_find(kind='name') to find IDs. Omit to profile the whole library installed on this server. | |
| response_format | No | Format of the human-readable text: 'markdown' (default) for display; 'json' the same data as one JSON code block; 'none' only a one-line pointer, leaving structuredContent as the whole answer. structuredContent is always returned, so a caller that parses it should pass 'none': the character budget counts both channels, and the unread copy otherwise spends most of it. Requires the 'response_format.none' capability (see shamela_get_brief). | markdown |
Output Schema
| Name | Required | Description |
|---|---|---|
| mode | No | literal | morphological. |
| root | No | Same as `term`, for older callers. |
| term | No | |
| by_book | No | Top 15 books by matching pages. |
| by_author | No | Top 15 authors. |
| truncated | No | |
| by_century | No | Hijri century, top 15. |
| total_hits | No | EXACT number of matching pages. |
| by_category | No | Category names (no ids), top 15. Reflects corpus size as well as topic, never authority: التفسير tops nearly every profile because tafsir is the largest body of text here. |
| scope_count | No | Books in scope; -1 when no scope was given. |
| coverage_cap | No | |
| rows_dropped | No | |
| accuracy_note | No | Morphological counts: the analyzer is ~0.80 accurate on classical Arabic, so read them as reach, not exact tallies. |
| books_matched | No | |
| total_counted | No | Hits folded into the distribution. |
| coverage_capped | No | True when the distribution is a top-coverage_cap sample: bucket counts are floors and shares indicative. |
| normalized_tokens | No | |
| truncation_message | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this as a safe, idempotent read; the description goes well beyond them with latency expectations (6–9 ms literal vs seconds morphological), the coverage_capped:true top-5,000 sampling contract where breakdown counts are floors while total_hits stays exact, and the EMPTY_SCOPE / zero-hit outcomes. This is disclosure an agent cannot get from the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the purpose and the key routing sentence, and every clause carries information (sampling caveat, error names, examples). It is dense and parenthetical-heavy, which costs some readability, but there is little slack to cut.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a nested-scoped statistics tool with an output schema, the description covers what is needed to call it correctly: scope composition and intersection, id-resolution path, mode semantics, capping behaviour, and named error states. Nothing an agent must know before invoking it is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds genuinely new detail: the literal-vs-morphological latency difference and the warning that morphological is often far broader than expected. It also supplies two concrete scope-shaped examples, though the per-parameter semantics largely restate the already thorough schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource — counts matching pages for a term plus its distribution by category, Hijri century, book and author — and immediately scopes it as 'Statistics only, never passages', which separates it from shamela_search without the agent needing to open either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: use shamela_search(match='words') to retrieve passages, run this first to size a topic and choose scope.category_ids, and map names to ids via shamela_find(kind='category'). It also states the when-not case for mode ('literal' before planning retrieval, 'morphological' only to trace a root), covering alternatives and exclusion conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
shamela_verify_quoteCheck whether a quotation occurs in the libraryARead-onlyIdempotentInspect
Checks whether an Arabic quotation occurs in the classical library and where: book, author, printed volume/page, edition, and whether the words are in the main text or in an editor's footnote. Use it on a passage an assistant quoted from memory. Matching ignores diacritics, tatweel and alef forms; exact says whether the page spells the words as given, and differences says how they differ. "not_found" means not found in the searched scope (the scope or bookId is named in the answer), not that the quotation is false or appears nowhere. matchedIn "foot" is the editor's words, not the author's. It reports where words are printed; it is not a ruling and does not say whether a passage is authentic. Needs at least 3 Arabic words; a shorter or non-Arabic quote returns a tool error naming the fix. Give scope or bookId to narrow it; with neither, the whole library is searched.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum matching pages to return (max 10). | |
| quote | Yes | The Arabic wording to look for, at least 3 words, as quoted; diacritics are optional. | |
| scope | No | Optional shelf to search. Ignored when bookId is given. hadith-primary — The eight primary hadith collections, edition-pinned; tafsir-canonical — Canonical tafsir — Ibn Kathir, al-Tabari, Ibn al-Jawzi first; fiqh-hanafi — Hanafi fiqh (+ usul, comparative); fiqh-maliki — Maliki fiqh (+ usul, comparative); fiqh-shafii — Shafi'i fiqh (+ usul, comparative); fiqh-hanbali — Hanbali fiqh (+ usul, comparative); fiqh-comparative — All four schools plus comparative and fatwa collections; aqeedah — Creed and sects; hadith-sciences — Hadith commentary, takhrij and the sciences of hadith; tafsir — The whole tafsir shelf and Quranic sciences; seerah — Prophetic biography, history and biographical dictionaries; lugha — Arabic language, lexicons, grammar and adab | |
| bookId | No | Optional: search this one book (Shamela's book id, as in a result's bookId). Wins over scope. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | The caveats to carry with the verdict. |
| matches | No | Up to `limit` pages, in the library's order; empty when not_found. |
| verdict | No | found: pages in the searched scope carry the words in this order. not_found: none does, in that scope only; never a statement that the quotation is false. |
| searched | No | What was searched. Carry it with any not_found. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Well beyond the readOnly/idempotent annotations, it explains matching normalization (diacritics, tatweel, alef forms), what 'exact' and 'differences' mean, that matchedIn 'foot' is the editor's words not the author's, and the critical caveat that 'not_found' means only not-found-in-scope. It also discloses the preconditions (3+ Arabic words) and the error behavior with the fix named, plus the epistemic limit ('not a ruling', 'does not say whether a passage is authentic').
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the outcome and immediately followed by the when-to-use sentence; every caveat after that (not_found semantics, foot vs. text, authenticity disclaimer) carries decision-relevant weight. The disclaimer is stated twice in near-equivalent wording ('not that the quotation is false' / 'not a ruling'), which is the only wasted space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a verification tool with four parameters, an output schema, and full annotation coverage, nothing an agent needs before calling is absent: purpose, preconditions, error behavior, scope defaults, and the interpretation of the ambiguous result fields are all present. The output schema handles the return shape, and the description covers the parts of the result most likely to be misread.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the structured fields already carry the parameter definitions and the scope enum. The description adds real operational meaning on top: the precedence rule is restated in behavioral terms, the no-parameter default (whole library searched) is spelled out, and the 3-word minimum is framed as a hard error with a fix rather than a silent filter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Checks whether an Arabic quotation occurs in the classical library') plus the shape of the answer (book, author, volume/page, edition, main text vs. footnote). It implicitly separates itself from the keyword-search siblings by framing the use case as verifying a passage quoted from memory, but it never names those siblings the way a 5 would.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use it on a passage an assistant quoted from memory' states the triggering situation clearly, and the closing sentence explains the scope/bookId narrowing decision and the default (whole library). It stops short of naming an alternative tool or stating when not to use this one.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
- Changed
fetch1 field changed- changed
Output schema / properties / url / descriptionPrevious value: -"The same page on shamela.ws."New value: +"The same page in the Quran Gallery Maktabah reader."
- Changed
search1 field changed- changed
Output schema / properties / results / items / properties / url / descriptionPrevious value: -"The same page on shamela.ws."New value: +"The same page in the Quran Gallery Maktabah reader."
- Changed
shamela_search_library1 field changed- changed
Output schema / properties / passages / items / properties / sourceUrl / descriptionPrevious value: -"The same page on shamela.ws."New value: +"The same page in the Quran Gallery Maktabah reader."
- Changed
shamela_verify_quote1 field changed- changed
Output schema / properties / matches / items / properties / sourceUrl / descriptionPrevious value: -"The same page on shamela.ws."New value: +"The same page in the Quran Gallery Maktabah reader."
1 tool update
- Added
shamela_verify_quote
51 tool updates
- Changed
fetch12 fields changed- changed
Input schema / properties / id / descriptionPrevious value: -"A document id from `search`, e.g. \"117359:1796\"."New value: +"Page id \"{bookId}:{pageId}\", e.g. \"1681:10\" — Shamela internal ids from a `search` result, not printed page numbers. Malformed or unknown ids return a tool error." - added
Output schema / properties / id / descriptionAdded value: +"\"{bookId}:{pageId}\", normalised." - added
Output schema / properties / metadata / properties / authorDied / descriptionAdded value: +"Year of death in AH, or null." - added
Output schema / properties / metadata / properties / edition / descriptionAdded value: +"Omitted when the library records none." - added
Output schema / properties / metadata / properties / editor / descriptionAdded value: +"Omitted when the library records none." - added
Output schema / properties / metadata / properties / printedPage / descriptionAdded value: +"Volume and page as the printing paginates it, or null." - added
Output schema / properties / metadata / properties / publisher / descriptionAdded value: +"Omitted when the library records none." - removed
Output schema / properties / metadata / requiredRemoved value: -[ - "bookId", - "pageId", - "book", - "author", - "authorDied", - "printedPage", - "hasFootnotes", - "complete" -] - changed
Output schema / properties / text / descriptionPrevious value: -"Main text, then the footnotes under their own label."New value: +"Main text, then the footnotes under their own label (the editor's words). When metadata.complete is false it ends with the shamela_read(unit='page') call that continues it." - added
Output schema / properties / title / descriptionAdded value: +"\"{book} — {author} ({volume}/{page})\"." - added
Output schema / properties / url / descriptionAdded value: +"The same page on shamela.ws." - removed
Output schema / requiredRemoved value: -[ - "id", - "title", - "text", - "url", - "metadata" -]
- Changed
search6 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Arabic search text — a quoted wording or a topic."New value: +"Arabic search text, e.g. \"إنما الأعمال بالنيات\"; 2-6 words work best. Quote the wording if known, else name the topic." - added
Output schema / properties / results / descriptionAdded value: +"At most 10 pages; empty when no page carries the words." - added
Output schema / properties / results / items / properties / title / descriptionAdded value: +"\"{book} — {author} ({volume}/{page})\", plus [footnote match], [token match] or [near match] when the match is weaker than the exact phrase in the main text." - added
Output schema / properties / results / items / properties / url / descriptionAdded value: +"The same page on shamela.ws." - removed
Output schema / properties / results / items / requiredRemoved value: -[ - "id", - "title", - "url" -] - removed
Output schema / requiredRemoved value: -[ - "results" -]
- Removed
search_library - Removed
shamela_books_by_period - Removed
shamela_brief - Added
shamela_cite - Added
shamela_find - Removed
shamela_get_author - Removed
shamela_get_aya - Removed
shamela_get_book - Removed
shamela_get_book_parts - Removed
shamela_get_book_section - Removed
shamela_get_books_for_hadith - Added
shamela_get_brief - Removed
shamela_get_citation - Added
shamela_get_details - Removed
shamela_get_isnad - Removed
shamela_get_narrator - Removed
shamela_get_page - Removed
shamela_get_page_services - Removed
shamela_get_pages_range - Removed
shamela_get_tafseer_of_aya - Removed
shamela_get_tafseer_texts - Removed
shamela_get_toc - Removed
shamela_list_categories - Removed
shamela_list_tafsirs_for_aya - Added
shamela_lookup_hadith - Added
shamela_lookup_quran - Added
shamela_lookup_rijal - Added
shamela_lookup_tafsir - Added
shamela_read - Removed
shamela_recon - Removed
shamela_resolve - Removed
shamela_resolve_printed_page - Removed
shamela_resolve_work - Removed
shamela_root_stats - Added
shamela_search - Removed
shamela_search_authors - Removed
shamela_search_batch - Removed
shamela_search_books - Removed
shamela_search_boolean - Removed
shamela_search_exact - Removed
shamela_search_hadith - Removed
shamela_search_isnad - Added
shamela_search_library - Removed
shamela_search_narrators - Removed
shamela_search_pages - Removed
shamela_search_phrase - Removed
shamela_search_quran - Removed
shamela_search_titles - Added
shamela_survey_topic
39 tool updates
- First observed
fetch - First observed
search - First observed
search_library - First observed
shamela_books_by_period - First observed
shamela_brief - First observed
shamela_get_author - First observed
shamela_get_aya - First observed
shamela_get_book - First observed
shamela_get_book_parts - First observed
shamela_get_book_section - First observed
shamela_get_books_for_hadith - First observed
shamela_get_citation - First observed
shamela_get_isnad - First observed
shamela_get_narrator - First observed
shamela_get_page - First observed
shamela_get_page_services - First observed
shamela_get_pages_range - First observed
shamela_get_tafseer_of_aya - First observed
shamela_get_tafseer_texts - First observed
shamela_get_toc - First observed
shamela_list_categories - First observed
shamela_list_tafsirs_for_aya - First observed
shamela_recon - First observed
shamela_resolve - First observed
shamela_resolve_printed_page - First observed
shamela_resolve_work - First observed
shamela_root_stats - First observed
shamela_search_authors - First observed
shamela_search_batch - First observed
shamela_search_books - First observed
shamela_search_boolean - First observed
shamela_search_exact - First observed
shamela_search_hadith - First observed
shamela_search_isnad - First observed
shamela_search_narrators - First observed
shamela_search_pages - First observed
shamela_search_phrase - First observed
shamela_search_quran - First observed
shamela_search_titles
Publisher details
- Operator
- Quran Gallery · Publisher source
- Operator website
- https://qurangallery.com · Publisher source
- Vendor relationship
- First-party · Publisher source
- Documentation
- https://github.com/qurangallery/kb-mcp · Publisher source
- Trust center
- Not available
- Restrictions
- No account, API key or paid plan needed. Keyless use is limited to 10 tool calls a minute and 200 a day per IP; an optional free key raises this to 60 a minute. Queries must be in Arabic. · Publisher source
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceRemote MCP server that lets AI assistants read tracked competitive intelligence — competitor news, reviews, website changes, social posts and ads — and act on it by managing projects, competitors, battle cards, reports and canvases. Every answer carries a source and a date, and write actions only publish when explicitly shared.MIT
- AlicenseCqualityCmaintenanceCompetitor Monitor AI - MCP server providing AI-powered tools and automation by MEOK AI Labs112 npm29 PyPIMIT
- AlicenseAqualityDmaintenanceEnables brand visibility monitoring across major AI platforms like ChatGPT, Claude, Gemini, and Perplexity. It allows users to track visibility scores, analyze competitor data, and receive actionable insights to improve AI-generated brand recommendations.1623 npm1MIT

industrylens-mcpofficial
AlicenseNot gradedqualityBmaintenanceBrowse IndustryLens's published competitive-intelligence reports and head-to-head competitor comparisons from any AI agent — real, source-backed data.MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.