Skip to main content
Glama
This connector has been deprecated

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

Ownership verified
Status
Healthy
Uptime
99.8% over 25 days
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
ChatGPT
–
Claude
–

TDQS

A4.4/5.0

Scored across 15 tools

Disambiguation4/5

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.

Naming Consistency4/5

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.

Tool Count4/5

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.

Completeness5/5

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 tools
fetchRead a library pageA
Read-onlyIdempotent
Inspect

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.

NameRequiredDescriptionDefault
idYesPage 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

NameRequiredDescription
idNo"{bookId}:{pageId}", normalised.
urlNoThe same page in the Quran Gallery Maktabah reader.
textNoMain 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.
titleNo"{book} — {author} ({volume}/{page})".
metadataNo

TDQS

A4.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

shamela_citeFormat a citation or resolve a printed pageA
Read-onlyIdempotent
Inspect

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.

NameRequiredDescriptionDefault
modeNoSelects what the call does: citation | printed_page. Default citation.
pageNoThe 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.)
partNoThe 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.)
textNoOptional 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.)
styleNoCitation 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_idNo[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_idNoOptional 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_formatNoFormat 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

NameRequiredDescription
notesNo[mode=citation] Missing citation fields and fallbacks; never fill them in. [mode=printed_page] Guidance on reading the result.
styleNo'shamela', 'short', 'full', 'bibtex' or 'ris'. (mode=citation only.)
statusNo'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_idNoCatalogue book id. (mode=printed_page only.)
citableNoFalse when the numbers are Shamela's own, not a printed edition's. (mode=printed_page only.)
matchesNoOne row per page id. (mode=printed_page only.)
page_idsNoEvery 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_nameNoCatalogue title of the book (Arabic). (mode=printed_page only.)
formattedNoThe citation text in the requested style. (mode=citation only.)
truncatedNo
componentsNoThe parts the citation was built from. (mode=citation only.)
page_rangeNoOn page_not_in_part: the printed range that exists in that part. (mode=printed_page only.)
rows_droppedNo
page_resolvedNoTrue 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_matchedNoDistinct parts matched; more than one means the number is ambiguous across volumes. (mode=printed_page only.)
requested_pageNoPrinted page requested. (mode=printed_page only.)
requested_partNoPart label requested; null when omitted. (mode=printed_page only.)
available_partsNoOn part_not_found: the part labels the book uses. (mode=printed_page only.)
truncation_messageNo

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 namesA
Read-onlyIdempotent
Inspect

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').

NameRequiredDescriptionDefault
kindNoSelects what the call does: book | heading | author | category | work | name | period. Default book.
typeNo'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.)
limitNo[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.)
queryNo[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.)
scopeNo[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.)
titleNoThe 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.)
authorNoThe 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.)
offsetNoNumber 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_toNoHijri year, inclusive UPPER bound on the MAIN AUTHOR's death year (author.death_number). Pair with died_from. (kind=period only.)
editionNoA 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.)
optionsNo[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_fromNoHijri 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_idNoOptional: 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_toNoHijri 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_fromNoHijri 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_countsNoIf 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_onlyNo[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_formatNoFormat 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

NameRequiredDescription
booksNo[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.)
matchNoThe single entry, when status is 'exact'. (kind=work only.)
notesNoGuidance on using the result. (kind=work only.)
queryNoThe query as received. (kind=book|heading|author|name only.)
titleNoTitle as parsed from the request. (kind=work only.)
totalNo[kind=category] Categories listed. [kind=period] Books satisfying every bound. (kind=category|period only.)
authorNoAuthor filter applied; null when none. (kind=work only.)
filterNoEcho of the applied constraints. (kind=period only.)
offsetNo[kind=book|heading|author] Offset this page started at. [kind=period] Rows skipped before this page. (kind=book|heading|author|period only.)
reasonNoWhen not_found: 'no_title_match', 'author_mismatch' or 'edition_not_found'. (kind=work only.)
statusNo'exact' — use `match`; 'ambiguous' — see `ambiguity`; 'not_found' — read `reason` (and available_editions for an unknown edition). (kind=work only.)
authorsNoAuthor matches, best first. (kind=name only.)
editionNoEdition requested; null when none. (kind=work only.)
resultsNo[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_idsNoThis page's ids, ready for scope.book_ids. (kind=period only.)
coverageNoHits rolled up by_category and by_century. (kind=book only.)
has_moreNo[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.)
rejectedNoEntries that matched the words but are not the cited work. (kind=work only.)
returnedNo[kind=book|heading|author] Rows in `results` on this call. [kind=period] Rows in this response. (kind=book|heading|author|period only.)
ambiguityNoWhen 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.)
truncatedNo
candidatesNoEntries that carry the requested title. (kind=work only.)
categoriesNoCategories by id. (kind=category only.)
total_hitsNoEvery match in scope, not just the rows returned. (kind=book|heading|author only.)
next_offsetNo[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_droppedNo
no_title_matchNoTrue 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_ceilingNoDeepest 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_truncatedNoTrue when the query had more words than are searched. (kind=book|heading|author only.)
downloaded_totalNoBooks installed on this server, whole library. (kind=category only.)
relaxed_of_termsNoWord count the relaxed match is measured against. (kind=book only.)
normalized_tokensNo[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_matchNoSet when no entry held every word: hits carry at least this many of `relaxed_of_terms`. (kind=book only.)
available_editionsNoWhen edition_not_found: the printings the catalogue does carry, shaped like candidates. (kind=work only.)
no_confident_matchNoPresent when nothing reached score 800 (no name carries the whole query): treat the hits as suggestions. (kind=name only.)
truncation_messageNo

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 pitfallsA
Read-onlyIdempotent
Inspect

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'}.

NameRequiredDescriptionDefault
response_formatNoFormat 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

NameRequiredDescription
trapsNo
limitsNoNumeric server limits by name.
truncatedNo
brief_hashNoDigest of every other field; re-fetch only when it changes.
capabilitiesNoArguments and response fields this build supports; gate new arguments on these.
rows_droppedNo
tool_aliasesNoRetired tool names mapped to their replacement and argument changes.
server_versionNoThis build's version.
truncation_messageNo

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 detailsA
Read-onlyIdempotent
Inspect

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.

NameRequiredDescriptionDefault
kindNoSelects what the call does: book | author. Default book.
book_idNoThe book id (e.g. 9942). (kind=book only.)
author_idNoThe 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_booksNoIf 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_coverNoAttach 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_formatNoFormat 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

NameRequiredDescription
scanNoThe scanned printing Shamela holds; null when none. (kind=book only.)
booksNoThe author's books by ascending book_id; empty when include_books is false. (kind=author only.)
coverNoTitle-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.)
notesNoCaveats, including citation fields the catalogue lacks. (kind=book only.)
editorNoEditor (محقق) from the front matter; null when absent. (kind=book only.)
authorsNoAuthors, main author first. (kind=book only.)
book_idNoCatalogue book id. (kind=book only.)
editionNoEdition read from the book's front matter; null when absent. Never invent one. (kind=book only.)
printedNo1 when page numbers follow a printed edition; otherwise Shamela numbers the pages itself. (kind=book only.)
categoryNoCategory name. (kind=book only.)
author_idNoAuthor id. (kind=author only.)
availableNoTrue when Shamela offers the book for download. (kind=book only.)
book_dateNoShamela «تاريخ الكتاب», 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_nameNoCatalogue title of the book (Arabic). (kind=book only.)
book_typeNoNumeric book type. (kind=book only.)
pdf_linksNoRaw scan descriptor from the catalogue; prefer `scan`. (kind=book only.)
publisherNoPublisher from the front matter; null when absent. (kind=book only.)
sub_booksNoCatalogue ids of books bound inside this one. (kind=book only.)
truncatedNo
book_countNoNumber of catalogue books (main or co-author). (kind=author only.)
death_textNoDeath date as display text. (kind=author only.)
death_yearNoHijri death year; null when unknown or living. (kind=author only.)
downloadedNoTrue only when the text is installed on this server and has pages. (kind=book only.)
same_groupNoOther 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_nameNoAuthor name. (kind=author only.)
category_idNoCategory id (see shamela_find(kind='category')). (kind=book only.)
rows_droppedNo
content_statusNo'readable', 'downloaded_no_pages' or 'not_downloaded'. (kind=book only.)
book_type_labelNoBook type in Arabic: printed, manuscript, journal, thesis, electronic or audio. (kind=book only.)
publication_dateNoHijri publication date, DDMMYYYY, from meta_data, when recorded. (kind=book only.)
truncation_messageNo

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 itA
Read-onlyIdempotent
Inspect

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').

NameRequiredDescriptionDefault
modeNoSelects what the call does: search | sources. Default search.
limitNoMaximum number of results to return (1-100, default 20). (mode=search only.)
queryNoThe 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_keyNoNumeric 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_onlyNoIf 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_formatNoFormat 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_scannedNoHow 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_categoriesNoSearch 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

NameRequiredDescription
queryNoThe query as received. (mode=search only.)
totalNoDistinct books carrying the key, installed or not. (mode=sources only.)
matchesNoMatching 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.)
relaxedNoPresent when the full text matched nothing and one word was dropped. (mode=search only.)
resultsNoOne row per book, in index order, with its first page for the hadith. (mode=sources only.)
takhrijNoCross-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.)
returnedNoRows in `results` after downloaded_only. (mode=sources only.)
searchedNo'hadith_shelves' (default) or 'whole_library' (search_all_categories). (mode=search only.)
truncatedNo
hadith_keyNo (mode=sources only.)
rows_droppedNo
index_entriesNoRaw index rows behind `total`. (mode=sources only.)
pages_scannedNoTop matches read for hadith keys (<= max_pages_scanned). (mode=search only.)
books_searchedNoBooks the text search covered: the hadith shelves (كتب السنة، شروح الحديث، التخريج والأطراف، علوم الحديث), 1,957 here. (mode=search only.)
key_index_booksNoBooks 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_matchesNoEvery page matching the text in the searched shelves. (mode=search only.)
truncation_messageNo
takhrij_from_key_indexNoTrue 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

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 ayahA
Read-onlyIdempotent
Inspect

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').

NameRequiredDescriptionDefault
ayaNoAya number within the surah, 1..N. Pair with `surah`. (mode=aya only.)
modeNoSelects what the call does: search | aya. Default search.
countNoHow 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.)
limitNoMaximum number of results to return (1-100, default 20). (mode=search only.)
queryNoArabic 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.)
surahNoSurah number 1..114. Pair with `aya`. E.g. {surah:55, aya:1} = Ar-Rahman 1. (mode=aya only.)
aya_idNoCumulative aya id, 1..6236. Mutually exclusive with surah/aya. E.g. 1 = al-Fatiha 1 (the basmala). (mode=aya only.)
offsetNoNumber 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.)
optionsNoCurrently 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_formatNoFormat 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

NameRequiredDescription
ayaNoVerse number within the surah. (mode=aya only.)
bodyNoStandard Egyptian imla'i spelling, Hafs from Asim — the form text search matches. (mode=aya only.)
amiriNoUthmani-script rendering (Amiri), for display to the reader. (mode=aya only.)
majmaNoKFQPC Mushaf rendering. (mode=aya only.)
queryNoThe query as received. (mode=search only.)
surahNoSurah number, 1..114. (mode=aya only.)
aya_idNoCumulative verse id, 1..6236. (mode=aya only.)
offsetNoOffset this page started at. (mode=search only.)
versesNoThe requested run in order; the top-level fields repeat verses[0]. (mode=aya only.)
resultsNoVerses 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_moreNoTrue when another page exists; call again with `next_offset`. (mode=search only.)
returnedNo[mode=search] Rows in `results` on this call. [mode=aya] Number of verses in `verses`.
truncatedNo
surah_ayatNoTotal verses in the first verse's surah, so you can ask for the rest with `count`. (mode=aya only.)
surah_nameNoArabic surah name. (mode=aya only.)
total_hitsNoEvery match in scope, not just the rows returned. (mode=search only.)
next_offsetNoOffset of the next page. Absent on the last page. (mode=search only.)
rows_droppedNo
paging_ceilingNoDeepest offset paging can reach. Present only when the request went past it: narrow the scope instead of paging further. (mode=search only.)
query_form_hitsNoVerses 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_truncatedNoTrue when the query had more words than are searched. (mode=search only.)
stem_expanded_toNoSingle-word queries: the extra forms searched beyond the word as typed. (mode=search only.)
normalized_tokensNoThe query after Arabic folding, as actually searched. (mode=search only.)
truncation_messageNo
total_hits_completeNoFalse when total_hits is a lower bound. (mode=search only.)

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents 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.

Purpose5/5

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.

Usage Guidelines5/5

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 isnadsA
Read-onlyIdempotent
Inspect

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) or transmission [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').

NameRequiredDescriptionDefault
modeNoSelects what the call does: narrators | narrator | isnad_search | isnad. Default narrators.
limitNo[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.)
queryNoPart 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_nNoHow many teachers and how many students to return, most frequent first (1-100, default 15). (mode=narrator only.)
offsetNo[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_idNoBook 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_idNoShamela 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.)
containsNoNarrator 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_resultsNoChains to return per page (1-100, default 20). Chains come in index order. (mode=isnad_search only.)
narrator_idNoThe 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_variantsNoCap on returned variant routes (1-200, default 20). `variants.truncated` reports when more exist. (mode=isnad only.)
transmissionNoPairs [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_idsNoRestrict 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_networkNoInclude 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_formatNoFormat 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_variantsNoAlso 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

NameRequiredDescription
nameNo (mode=narrator only.)
noteNo (mode=narrator only.)
queryNo (mode=narrators only.)
chainsNoChains printed on this page. (mode=isnad only.)
offsetNoRows skipped before this page. (mode=narrators|narrator|isnad_search only.)
tabaqaNoGeneration, per Taqrib al-Tahdhib. (mode=narrator only.)
book_idNo (mode=isnad only.)
networkNoIsnad-index network; null when include_network is false. (mode=narrator only.)
page_idNo (mode=isnad only.)
resultsNo[mode=narrators] Most-documented narrator first, earliest death year breaking ties. [mode=isnad_search] Chains in index order. (mode=narrators|isnad_search only.)
summaryNokunya, nasab, cities, relations — whatever the register holds. (mode=narrator only.)
containsNo (mode=isnad_search only.)
has_moreNoTrue when more rows exist past this page. (mode=narrators|narrator|isnad_search only.)
returnedNoRows in this response. (mode=narrators|narrator|isnad_search only.)
variantsNoOther 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_nameNo (mode=narrator only.)
truncatedNo
death_yearNo (mode=narrator only.)
jarh_tadilNoThis 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_hitsNoChains matching, before paging. (mode=isnad_search only.)
narrator_idNo (mode=narrator only.)
next_offsetNoOffset for the next page; present only when has_more is true. (mode=narrators|narrator|isnad_search only.)
hadeeth_keysNo (mode=isnad only.)
hadith_notesNoFawa'id on audition, irsal and implicit tawthiq: the evidence for whether a chain is connected. (mode=narrator only.)
rows_droppedNo
transmissionNo (mode=isnad_search only.)
grade_dhahabiNo (mode=narrator only.)
total_criticsNo (mode=narrator only.)
total_matchesNo (mode=narrators only.)
paging_ceilingNoPresent when offset passed the deepest reachable row. (mode=isnad_search only.)
total_verdictsNo (mode=narrator only.)
grade_ibn_hajarNo (mode=narrator only.)
no_isnad_reasonNono_marker_on_page (the page's own service annotations carry no isnad marker) | marked_but_unindexed | null. (mode=isnad only.)
chains_truncatedNo (mode=isnad only.)
no_isnad_indexedNo (mode=isnad only.)
page_isnad_markersNo (mode=isnad only.)
truncation_messageNo
total_chains_on_pageNo (mode=isnad only.)
absent_from_isnad_indexNoTrue when no indexed chain names this narrator; null when not computed. (mode=narrator only.)

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 ayahA
Read-onlyIdempotent
Inspect

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]}.

NameRequiredDescriptionDefault
ayaNoVerse number within the surah, 1..N; requires `surah`.
modeNoSelects what the call does: coverage | texts. Default coverage.
surahNoSurah number 1..114; requires `aya`. Alternative to aya_id.
aya_idNoCumulative 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_idsNoRestrict 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_sourcesNoMaximum 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_onlyNoIf 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_formatNoFormat 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

NameRequiredDescription
ayaNo
noteNoCaveat: the index is curated, so unknown status is not absence.
booksNoEvery tafsir-shelf book plus index hits, ordered by status, installed first, then book_id; a long list is cut (rows_dropped). (mode=coverage only.)
surahNo
totalNoDistinct books the index maps to this verse, installed or not. (mode=coverage only.)
aya_idNoCumulative verse id, 1..6236.
totalsNoCount of books in each coverage status. (mode=coverage only.)
fetchedNoSources whose text was read. (mode=texts only.)
resultsNoThe index hits alone, repeating books[] rows; filtered by downloaded_only (false adds hits whose text is not installed, downloaded:false). (mode=coverage only.)
sourcesNoRead 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.)
_displayNo (mode=texts only.)
returnedNoRows in `results`. (mode=coverage only.)
truncatedNo
surah_nameNo
rows_droppedNo
coverage_noteNo (mode=coverage only.)
index_entriesNoRaw index rows; exceeds `total` when commentary spans pages. (mode=coverage only.)
total_indexedNoBooks the curated index maps to this verse. (mode=texts only.)
remaining_book_idsNoIndexed sources not read in this call; pass as book_ids to continue. (mode=texts only.)
truncation_messageNo

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 contentsA
Read-onlyIdempotent
Inspect

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').

NameRequiredDescriptionDefault
unitNoSelects what the call does: page | range | section | toc | parts | services. Default page.
countNoHow 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.)
depthNoLevels 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_idNoThe book id, from shamela_find(kind='book'), shamela_find(kind='work') or shamela_find(kind='name'). Installed ids: shamela_list_downloaded_books.
page_idNo[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_idNoThe 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_partNoFor 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_htmlNo[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_pagesNoCap 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_idNoTitle id whose children to list; 0 (default) = top-level chapters. Ignored when containing_page_id is set. (unit=toc only.)
start_page_idNoFirst 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_formatNoFormat 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_idNoPage 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

NameRequiredDescription
rawNoThe raw service record, for debugging. (unit=services only.)
ayatNoCumulative aya ids (1-6236, 262 = 2:255) cited on the page, as stored; pass to shamela_lookup_quran(mode='aya'). (unit=services only.)
bodyNoMain text (matn), or the requested body_part of it. (unit=page only.)
footNoFootnotes (editor's words, not the author's); returned with body_part 1 only. (unit=page only.)
modeNo'subtree' (parent_id/depth) or 'ancestor_chain' (containing_page_id). (unit=toc only.)
partNoVolume/part label, e.g. '4'; null for single-volume books. (unit=page only.)
countNoPages actually returned (may be fewer than requested). (unit=range only.)
depthNoLevels expanded in subtree mode; null in ancestor_chain mode. (unit=toc only.)
esnadNoRaw 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.)
pagesNoPages in reading order. (unit=range|section only.)
partsNoVolumes 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.)
titlesNoSubtree mode: the headings, nested via children. Empty under a leaf. (unit=toc only.)
book_idNoCatalogue book id.
commentNoUser annotation; returned with body_part 1 only. (unit=page only.)
hadeethNoNumeric hadith keys, as stored; pass to shamela_lookup_hadith(mode='sources'). (unit=services only.)
page_idNo[unit=page] Internal page id that was read. [unit=services] Page id. (unit=page|services only.)
_displayNoAdvice 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_moreNoTrue when pages exist after the last one returned. (unit=range only.)
title_idNoHeading that was read. (unit=section only.)
body_partNo1-based part of the body returned. (unit=page only.)
book_nameNoCatalogue title of the book (Arabic). (unit=page|range|section|toc|parts only.)
parent_idNoParent expanded in subtree mode; null in ancestor_chain mode. (unit=toc only.)
truncatedNoTrue when fewer pages were returned than the section has.
title_textNoHeading text. (unit=section only.)
author_nameNoMain author name. (unit=page|range|section only.)
end_page_idNoLast page id of the section. (unit=section only.)
esnad_countNoNumber of isnad markers. (unit=services only.)
total_pagesNoPage records in the book. (unit=parts only.)
has_servicesNoFalse when the page carries no markers (common outside hadith works). (unit=services only.)
next_page_idNoNext existing page id; null at the end. (unit=page only.)
prev_page_idNoPrevious existing page id (ids have gaps); null at the start. (unit=page only.)
printed_pageNoPrinted page label as Shamela renders it, e.g. '4/ 405'; null when the page has no printed number. (unit=page only.)
rows_droppedNo
body_has_moreNoTrue when another body_part follows. (unit=page only.)
category_pathNoCategory names, broadest first. (unit=page only.)
start_page_idNo[unit=range] First page id requested. [unit=section] First page id of the section. (unit=range|section only.)
ancestor_chainNoancestor_chain mode: headings enclosing the page, root to leaf. (unit=toc only.)
is_multi_volumeNoTrue when the pages carry more than one part label. (unit=parts only.)
body_total_partsNoHow many parts the body is split into. (unit=page only.)
containing_titlesNoChapter headings enclosing the page, root to leaf. (unit=page only.)
next_start_page_idNo[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_messageNo
total_pages_in_sectionNoPages the whole section spans. (unit=section only.)

TDQS

A4.9/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_search_librarySearch the classical Islamic libraryA
Read-onlyIdempotent
Inspect

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.

NameRequiredDescriptionDefault
limitNoMaximum passages to return (max 10).
queryYesArabic search text. A quoted wording works best; a topic also works.
scopeYeshadith-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

NameRequiredDescription
noteNoPresent only when the result needs a caveat; carry it with the passages.
scopeNoThe scope searched, as sent.
passagesNoBest 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.
totalMatchesNoMatching pages the library verified in the scope before the limit, or null.
booksSearchedNoBooks in the searched scope, or null when the library did not say.
relaxedToTokensNoTrue when the exact phrase was not found and a looser word search answered.

TDQS

A4.6/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 libraryA
Read-onlyIdempotent
Inspect

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}}.

NameRequiredDescriptionDefault
modeNo'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
termYesArabic 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.
scopeNoRestrict 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_formatNoFormat 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

NameRequiredDescription
modeNoliteral | morphological.
rootNoSame as `term`, for older callers.
termNo
by_bookNoTop 15 books by matching pages.
by_authorNoTop 15 authors.
truncatedNo
by_centuryNoHijri century, top 15.
total_hitsNoEXACT number of matching pages.
by_categoryNoCategory 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_countNoBooks in scope; -1 when no scope was given.
coverage_capNo
rows_droppedNo
accuracy_noteNoMorphological counts: the analyzer is ~0.80 accurate on classical Arabic, so read them as reach, not exact tallies.
books_matchedNo
total_countedNoHits folded into the distribution.
coverage_cappedNoTrue when the distribution is a top-coverage_cap sample: bucket counts are floors and shares indicative.
normalized_tokensNo
truncation_messageNo

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 libraryA
Read-onlyIdempotent
Inspect

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.

NameRequiredDescriptionDefault
limitNoMaximum matching pages to return (max 10).
quoteYesThe Arabic wording to look for, at least 3 words, as quoted; diacritics are optional.
scopeNoOptional 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
bookIdNoOptional: search this one book (Shamela's book id, as in a result's bookId). Wins over scope.

Output Schema

NameRequiredDescription
noteNoThe caveats to carry with the verdict.
matchesNoUp to `limit` pages, in the library's order; empty when not_found.
verdictNofound: 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.
searchedNoWhat was searched. Carry it with any not_found.

TDQS

A4.3/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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.

  1. 4 tool updates
    • Changedfetch1 field changed
      • changedOutput schema / properties / url / description
        Previous value: -"The same page on shamela.ws."New value: +"The same page in the Quran Gallery Maktabah reader."
    • Changedsearch1 field changed
      • changedOutput schema / properties / results / items / properties / url / description
        Previous value: -"The same page on shamela.ws."New value: +"The same page in the Quran Gallery Maktabah reader."
    • Changedshamela_search_library1 field changed
      • changedOutput schema / properties / passages / items / properties / sourceUrl / description
        Previous value: -"The same page on shamela.ws."New value: +"The same page in the Quran Gallery Maktabah reader."
    • Changedshamela_verify_quote1 field changed
      • changedOutput schema / properties / matches / items / properties / sourceUrl / description
        Previous value: -"The same page on shamela.ws."New value: +"The same page in the Quran Gallery Maktabah reader."
  2. 1 tool update
    • Addedshamela_verify_quote
  3. 51 tool updates
    • Changedfetch12 fields changed
      • changedInput schema / properties / id / description
        Previous 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."
      • addedOutput schema / properties / id / description
        Added value: +"\"{bookId}:{pageId}\", normalised."
      • addedOutput schema / properties / metadata / properties / authorDied / description
        Added value: +"Year of death in AH, or null."
      • addedOutput schema / properties / metadata / properties / edition / description
        Added value: +"Omitted when the library records none."
      • addedOutput schema / properties / metadata / properties / editor / description
        Added value: +"Omitted when the library records none."
      • addedOutput schema / properties / metadata / properties / printedPage / description
        Added value: +"Volume and page as the printing paginates it, or null."
      • addedOutput schema / properties / metadata / properties / publisher / description
        Added value: +"Omitted when the library records none."
      • removedOutput schema / properties / metadata / required
        Removed value: -[
        -  "bookId",
        -  "pageId",
        -  "book",
        -  "author",
        -  "authorDied",
        -  "printedPage",
        -  "hasFootnotes",
        -  "complete"
        -]
      • changedOutput schema / properties / text / description
        Previous 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."
      • addedOutput schema / properties / title / description
        Added value: +"\"{book} — {author} ({volume}/{page})\"."
      • addedOutput schema / properties / url / description
        Added value: +"The same page on shamela.ws."
      • removedOutput schema / required
        Removed value: -[
        -  "id",
        -  "title",
        -  "text",
        -  "url",
        -  "metadata"
        -]
    • Changedsearch6 fields changed
      • changedInput schema / properties / query / description
        Previous 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."
      • addedOutput schema / properties / results / description
        Added value: +"At most 10 pages; empty when no page carries the words."
      • addedOutput schema / properties / results / items / properties / title / description
        Added 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."
      • addedOutput schema / properties / results / items / properties / url / description
        Added value: +"The same page on shamela.ws."
      • removedOutput schema / properties / results / items / required
        Removed value: -[
        -  "id",
        -  "title",
        -  "url"
        -]
      • removedOutput schema / required
        Removed value: -[
        -  "results"
        -]
    • Removedsearch_library
    • Removedshamela_books_by_period
    • Removedshamela_brief
    • Addedshamela_cite
    • Addedshamela_find
    • Removedshamela_get_author
    • Removedshamela_get_aya
    • Removedshamela_get_book
    • Removedshamela_get_book_parts
    • Removedshamela_get_book_section
    • Removedshamela_get_books_for_hadith
    • Addedshamela_get_brief
    • Removedshamela_get_citation
    • Addedshamela_get_details
    • Removedshamela_get_isnad
    • Removedshamela_get_narrator
    • Removedshamela_get_page
    • Removedshamela_get_page_services
    • Removedshamela_get_pages_range
    • Removedshamela_get_tafseer_of_aya
    • Removedshamela_get_tafseer_texts
    • Removedshamela_get_toc
    • Removedshamela_list_categories
    • Removedshamela_list_tafsirs_for_aya
    • Addedshamela_lookup_hadith
    • Addedshamela_lookup_quran
    • Addedshamela_lookup_rijal
    • Addedshamela_lookup_tafsir
    • Addedshamela_read
    • Removedshamela_recon
    • Removedshamela_resolve
    • Removedshamela_resolve_printed_page
    • Removedshamela_resolve_work
    • Removedshamela_root_stats
    • Addedshamela_search
    • Removedshamela_search_authors
    • Removedshamela_search_batch
    • Removedshamela_search_books
    • Removedshamela_search_boolean
    • Removedshamela_search_exact
    • Removedshamela_search_hadith
    • Removedshamela_search_isnad
    • Addedshamela_search_library
    • Removedshamela_search_narrators
    • Removedshamela_search_pages
    • Removedshamela_search_phrase
    • Removedshamela_search_quran
    • Removedshamela_search_titles
    • Addedshamela_survey_topic
  4. 39 tool updates
    • First observedfetch
    • First observedsearch
    • First observedsearch_library
    • First observedshamela_books_by_period
    • First observedshamela_brief
    • First observedshamela_get_author
    • First observedshamela_get_aya
    • First observedshamela_get_book
    • First observedshamela_get_book_parts
    • First observedshamela_get_book_section
    • First observedshamela_get_books_for_hadith
    • First observedshamela_get_citation
    • First observedshamela_get_isnad
    • First observedshamela_get_narrator
    • First observedshamela_get_page
    • First observedshamela_get_page_services
    • First observedshamela_get_pages_range
    • First observedshamela_get_tafseer_of_aya
    • First observedshamela_get_tafseer_texts
    • First observedshamela_get_toc
    • First observedshamela_list_categories
    • First observedshamela_list_tafsirs_for_aya
    • First observedshamela_recon
    • First observedshamela_resolve
    • First observedshamela_resolve_printed_page
    • First observedshamela_resolve_work
    • First observedshamela_root_stats
    • First observedshamela_search_authors
    • First observedshamela_search_batch
    • First observedshamela_search_books
    • First observedshamela_search_boolean
    • First observedshamela_search_exact
    • First observedshamela_search_hadith
    • First observedshamela_search_isnad
    • First observedshamela_search_narrators
    • First observedshamela_search_pages
    • First observedshamela_search_phrase
    • First observedshamela_search_quran
    • First observedshamela_search_titles

Publisher details

Operator
Quran Gallery · Publisher source
Vendor relationship
First-party · 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

  • A
    license
    Not graded
    quality
    C
    maintenance
    Remote 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
  • A
    license
    A
    quality
    D
    maintenance
    Enables 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.
    16
    23 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Browse IndustryLens's published competitive-intelligence reports and head-to-head competitor comparisons from any AI agent — real, source-backed data.
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources