§1 and §3 describe what is shipped. §2 is a survey of the developer surfaces of established Islamic platforms; every external claim was read from the linked page on the date given, not from memory.
| Surface | Path | Notes |
|---|---|---|
| OpenAPI 3.1 document | GET /openapi.json |
generated by FastAPI; title «Basira API», version = backend/app/__init__.py |
| Interactive docs (Swagger UI) | GET /docs |
on unless BASIRA_DOCS=0; ReDoc disabled |
| Health gate | GET /health |
503 with error envelope until index loaded; counts, rss, build sha, provider names |
| Check text | POST /v1/check |
{text ≤ 5000, ui_lang, source_modality, options} → CheckResponse |
| Check image | POST /v1/check/image |
multipart image (+ ui_lang); returns ocr_text so the user can verify what was read (ADR-003) |
| Sources manifest | GET /v1/sources |
name, version/commit, licence + URL, record count |
| Message catalogue | GET /v1/messages/{ar|en} |
single source of all user-facing strings |
| Guard an AI answer | POST /v1/guard |
clear / flagged / no_quotes with fixed summaries (docs/GUARD.md) |
| Verification receipt | POST /v1/receipt, GET /v/{token}?h= |
stateless token; replay answers verified_now or stale (§3.3) |
| Grounding rules | GET /v1/rules |
the red lines and the four states, AR/EN, with safety_sha256 |
| Model configuration | GET /v1/models, PUT/DELETE /v1/models/config |
measured catalog; key stored server-side, always masked (docs/MODELS.md) |
| MCP server | /mcp |
six tools when BASIRA_MCP=1 (§3.1) |
Guards: CORS allow-list, rate limit 30/min per client (X-Eval-Key bypass), error envelope {error:{code,message_ar,message_en}}, class-only logging, no persistence.
The frontend links to /docs; in development Vite proxies /docs and /openapi.json to :8000, and in production
the single container serves both from the same origin.
| Platform | What they offer developers | What is worth adopting | What we must NOT copy |
|---|---|---|---|
| Quran Foundation / quran.com — api-docs.quran.foundation | Developer Console (app registration), Content APIs GET /content/api/v4/… with OAuth2 client-credentials, official JS/TS SDK (@quranjs/api) and Python SDK (quran-foundation-api on PyPI), User APIs (bookmarks…) behind OIDC |
Clear two-tier docs: «Quickstart in 5 minutes» + reference generated from the OpenAPI spec; typed SDK as the first-class path | User accounts / OAuth — Basira stores nothing, so there is no user data to protect; adding login would contradict SAFETY |
quran/quran-mcp (github.com/quran/quran-mcp, remote https://mcp.quran.ai) |
Remote streamable-HTTP MCP server; tools fetch_quran, search_tafsir, …; MCP resources and prompts; a middleware layer for rate limiting, grounding, logging; one-line client config for Claude Desktop / ChatGPT |
Remote-first MCP (no install), a grounding middleware that tells the model how to cite, and a documentation site served by the same process | Tafsir/translation tools — out of scope and would require us to serve interpretive text |
| hadith-mcp.org | Six read-only tools incl. fetch_grounding_rules (returned once per session: citation rules + limitations), fetch_hadith, search_hadith, fetch_cross_references, show_hadith (MCP app UI); a companion web app «verify AI citations quickly» with shareable proof links; explicit disclaimer that provenance tags are heuristics, not rulings |
fetch_grounding_rules pattern (we have the equivalent text in SAFETY §1.3 and transparency_notice); shareable, stateless proof links; the honesty of labelling algorithmic output as algorithmic |
Semantic (embedding) search as a verification primitive — non-deterministic; our matching stays deterministic (I1–I9) |
| sunnah.com — sunnah.com/developers | REST API documented on Stoplight; API key by GitHub issue; community reports slow/unanswered key requests (reddit, issue #2849, 2026-03) | Public OpenAPI reference | Gate-kept keys — Basira's check endpoint is public with rate limiting; eval key is for benchmarks only |
| dorar.net — article 389 «خدمة واجهة الموسوعة الحديثية API» | JSON(P) search widget for site owners; third parties wrap it (dorar-hadith-api) because the official one needs jQuery/JSONP |
The idea of an embeddable widget for other sites (§3.3) | Scraping or wrapping dorar — we only link to dorar search (referral URLs are built in backend/app/links.py) |
| hadeethenc.com | Bulk download page (used by us under their redistribution terms) | — | Showing the full HadeethEnc text by default; Basira ships HADEETHENC_MODE=link (grade + link) |
Conclusion of the survey. Every existing MCP/API in this space is a retrieval surface («give me ayah 2:255», «search hadith about …»). None offers a deterministic verification primitive («here is a text someone wrote — tell me byte-exactly where it departs from the Mushaf / the matn, without rewriting it»). That is the gap Basira fills, and it is what would make the MCP tool unique: an AI assistant can draft, then call Basira to check its own quotes before showing them to a user.
Status: live at /mcp when BASIRA_MCP=1 (otherwise a plain 404). backend/app/mcp_server.py, mounted inside the
FastAPI process, reads app.state.pipeline per call — one pipeline object serves REST and MCP (no second index load,
E-038). Streamable HTTP, stateless_http=True, JSON responses, SDK mcp 2.3.0 (MCPServer; the v1 FastMCP import no
longer exists). Tool errors reuse the API envelope {code, message_ar, message_en}; nothing internal leaks; nothing is stored.
| tool | input | output |
|---|---|---|
verify_text |
text, ui_lang |
compact verdicts per quotation + notices as sentences + determinism_hash |
verify_quote |
text, claimed_ref? («2:255», «البقرة: 255», «البخاري 1», «رواه مسلم»), ui_lang |
status, claimed_source_mismatch, the matched record verbatim |
guard_answer |
answer, ui_lang |
clear / flagged / no_quotes + counts + fixed summaries (docs/GUARD.md) |
list_sources |
— | manifest: id, version, licence, sha256 (incl. the 18 OHD files), live counts |
grounding_rules |
ui_lang |
fixed AR/EN instructions from SAFETY.md + safety_sha256 |
issue_receipt |
text, ui_lang |
stateless verification receipt (§3.3); same token as POST /v1/receipt |
Names deliberately differ from the design (check_text → verify_text) to read as verification next to the
association's retrieval tools. Tests: backend/tests/test_mcp.py (21, real MCP client over ASGI; REST and MCP verdicts byte-equal).
Client config: {"mcpServers":{"basira":{"url":"https://<host>/mcp","type":"http"}}} · local: http://localhost:8000/mcp.
Complementing mcp.islamiccontent.org (verified live 2026-10-05). Their server offers 11 tools, all retrieval
(search, fetch, get_quran_verses, list_quran_translations, get_quran_audio, get_hadith, browse_hadith_categories, browse_library, get_library_item, list_library_categories, list_languages); none takes user text and verifies it. The
intended loop for an assistant: fetch with theirs → answer → verify/guard with ours. scripts/mcp_demo.py does
exactly that; its unedited output:
$ cd backend && BASIRA_MCP=1 .venv/bin/uvicorn app.main:app --port 8000 # terminal 1
$ backend/.venv/bin/python scripts/mcp_demo.py # terminal 2
== Part 1: Basira MCP at http://localhost:8011/mcp
server: basira v0.2.0
tools/list: ['verify_text', 'verify_quote', 'guard_answer', 'list_sources', 'grounding_rules', 'issue_receipt']
grounding_rules: states=['found', 'partial_match', 'needs_review', 'not_found'] safety_sha256=4d5256783de4…
verify_text('قال تعالى: ﴿إن الله مع الصابرين﴾') → hash 5785aa4af67b…
• found quran reason=None سورة البقرة، الآية 153
source_text: يَٰٓأَيُّهَا ٱلَّذِينَ ءَامَنُوا۟ ٱسْتَعِينُوا۟ بِٱلصَّبْرِ وَٱلصَّلَو…
notice: النص المنقول جزء من الآية لا الآية كاملة؛ نص الآية كاملًا معروض بجانب نصك.
verify_text('قال تعالى: ﴿قل هو HELLO الله أحد﴾.') → hash 5a70649c0a33…
• needs_review quran reason=foreign_material سورة الإخلاص، الآية 1
source_text: بِسْمِ ٱللَّهِ ٱلرَّحْمَٰنِ ٱلرَّحِيمِ قُلْ هُوَ ٱللَّهُ أَحَدٌ
notice: داخل الاقتباس كلمات أو أرقام أو رموز ليست من النص (مظلّلة في نصك). أزلها ثم أعد الفحص.
verify_text('قال ﷺ: «الدين المعاملة»') → hash a4d5b77d78e2…
• not_found hadith_matn reason=None —
determinism: second call hash equal = True
guard_answer → flagged {'quotes': 3, 'found': 1, 'flagged': 2, 'by_status': {'found': 1, 'needs_review': 1, 'not_found': 1}}
The answer contains 3 quotation(s); 2 of them need review before publishing (not found verbatim in Basira's sources, or differing from the source text). Basira is a deterministic aid; "not found in our sources" is not a verdict on the text. Consult qualified scholars when in doubt.
== Part 2: integration with https://mcp.islamiccontent.org/mcp
remote tools (11): ['search', 'fetch', 'get_quran_verses', 'list_quran_translations', 'get_quran_audio', 'get_hadith', 'browse_hadith_categories', 'browse_library', 'get_library_item', 'list_library_categories', 'list_languages']
get_quran_verses input schema keys: ['surah', 'ayah', 'through', 'translation_key', 'language']
calling get_quran_verses({'surah': 2, 'ayah': 153, 'through': 153, 'translation_key': 'english_saheeh'})
remote returned 1036 chars: ["──────── RETRIEVED FROM QURANENC — published text ────────\n\n[Surah 2, translation \"english_saheeh\"]\n\n[EXACT] the verses and their published translation …
verse text → Basira: 'يَٰٓأَيُّهَا ٱلَّذِينَ ءَامَنُواْ ٱسۡتَعِينُواْ بِٱلصَّبۡرِ …'
• found quran reason=None Surah Al-Baqarah (2:153)
source_text: يَٰٓأَيُّهَا ٱلَّذِينَ ءَامَنُوا۟ ٱسْتَعِينُوا۟ بِٱلصَّبْرِ وَٱلصَّلَو…
determinism_hash 195a15343a45…
Reading: the verse text returned by get_quran_verses (QuranEnc's Uthmani encoding: U+06E1 small high dotless head of khah for sukun, plain U+0652 sukun elsewhere, U+0653 madda)
is confirmed found 2:153 by Basira against Tanzil's encoding — the strict tier's canonical composition (E-023/E-024)
is what makes two faithful encodings of the Mushaf agree. remote returned 1036 chars is their framed payload (header
- Arabic + Saheeh International translation); only the Arabic span is sent to
verify_text.
docs/API.md: quickstart, one example per endpoint captured from the real corpus, the four states, the error envelope, rate limits and the red lines (what the API never returns)./developerspage in the SPA: the quickstart, the MCP client config and a link to the OpenAPI reference.- OpenAPI examples are real request/response pairs (
backend/app/openapi_examples.json), never invented text. - Every response carries the
corpusblock andX-Basira-Determinism-Hash: the reproducibility contract.
- Stateless verification receipt:
POST /v1/receipt {text, ui_lang}→{receipt_id, determinism_hash, corpus, index_sha256, build_sha, issued_at, summary, quotes, token};GET /v/{token}?h=<hash>re-runs the whole pipeline and answersverified_now/stale.token = base64url(zlib(json{v:1,t,l}))— the receipt is the input; nothing is stored (dorar/hadith-mcp «shareable link» idea without their database). MCP toolissue_receipt. JSON only — the design agent renders/v/{token}later. docs/API.md §3.8. <script>widget for publishers: paste-box that posts to/v1/checkand renders the sameQuoteCard. Needs CORS allow-list per publisher and a size budget; not before the deploy target is known.
- OAuth / user accounts (nothing to protect; contradicts «لا نحفظ شيئًا»).
- Semantic/embedding search as a verification primitive (non-deterministic; I7 reproducibility).
- Serving tafsir, translations or any interpretive text (red line: never generate or curate religious text beyond the pinned corpora).
@BasiraCheckBot — integrations/telegram/ (README there). Forward any text or image; the bot calls POST /v1/check or POST /v1/check/image and renders the response with messages/ar.json only: status, verbatim source_text, reference, bold differences from diff, links, transparency line. No model in the bot, nothing stored. Run: docker compose --profile bot up. Decision: E-059.