bible.flogvit.com MCP server
Lets an AI assistant read and search the Bible on bible.flogvit.com: the open
OSNB, OSNN and OSEN translations, the Hebrew and Greek source texts, and the
site's study material. Every answer links back to the page it came from.
Address: https://mcp.bible.flogvit.com/mcp — Streamable HTTP, no account,
no key.
Connect an assistant
The full guide, for every client and in all eight languages, is
bible.flogvit.com/en/mcp. A browser that
opens https://mcp.bible.flogvit.com/ gets the short version of it. Both are
rendered from ../src/lib/mcp-info.ts and the mcp.* keys in
../src/lib/dictionaries-mcp.ts, and test/landing.test.ts holds the tool
list there against tools/list.
Claude (desktop app and claude.ai): Settings → Connectors → Add custom
connector. Paste the address, leave authentication empty.
ChatGPT: turn on developer mode under Settings → Apps & Connectors, then
create a connector with the address and no authentication.
Claude Code:
Cursor (~/.cursor/mcp.json):
VS Code (.vscode/mcp.json):
Then ask as you normally would — "what does John 3:16 say in the Greek?",
"where does the Bible talk about forgiveness?", "who was Tamar?". The assistant
picks the tools itself.
Without MCP — in a terminal, a script, or an agent that reads skills — the
same tools are the command line client flogvit-bible, with a skill and a
Claude Code plugin around it: ../cli/README.md.
The tools
References are read in English and Norwegian style alike — John 3:16-18,
Joh 3,16.18, 1 Cor 13:4-7, Gen 1:1-2:3, several separated by ; — and
book names in all eight site languages, plus the Norwegian letter names
(«Romerbrevet»).
Verse numbering. Every tool that takes or gives a verse reference has a
mapping argument: an id from list_verse_mappings (english_kj,
dnb2024_nb, …) or a short name (kjv, dnb2024). A reference is read in
that numbering and the answer is numbered in it, so "Mal 4:5" with kjv is
osnb's Malachi 3:23. The tools do no remapping of their own: a reference goes
through mapChapter(), as /api/chapter?mapping= does, and an osnb address
comes out through osnbToMapping(), the cross mapping /api/mappings/kvn/:id
builds its verseMap from (src/lib/verse-mapper.ts). Unlike the API, which
only knows the 13 named numberings, the MCP takes any of the 1158 mapping
files. That is why the caches in verse-mapper.ts have a cap (32).
Quoted Bible text carries its source line. The translations are CC BY 4.0, and
the attribution has to follow the text wherever the assistant puts it.
Releasing a new version
Every change a client can see — a tool added or removed, an argument, a
description — is a release, and the directories that list the server have to
follow it. They do not all get their data the same way:
- In the PR that changes the tools, raise the version —
SERVER_VERSION in
src/server.ts and version in server.json, which test/landing.test.ts
holds equal. The registry never accepts the same version twice. A new tool
or argument is a minor version (1.1.0 → 1.2.0); a removed tool or argument a
major one. Change description in server.json too if what the server does
has changed: it is what every directory shows, and at most 100 characters.
- Merge. The orchestra's deployer rolls out bibel and
bibel-mcp from the
same commit.
- After the rollout, publish to the registry:
It refuses while the live server still runs another version or other tools,
so it cannot announce what is not out. It logs in with
gh auth token
(gh must be logged in as flogvit; the namespace is io.github.flogvit)
and needs nothing installed.
- Press Request update on https://mcpservers.org/servers/bible-flogvit-com-en-mcp.
It is anonymous and takes effect at once, so press it only after the site
is out — pressed earlier, they re-read the old page. Their review takes up to
two weeks. The short description there is the one submitted in the form;
whether Request update refreshes it too is not known. To change it, email
[email protected].
- Check, about 30 minutes later:
Every line should say
ok. mcptry tools follows mcptry's own schedule and
can lag; "Connect live" on its page refreshes it. mcpservers.org sits behind
a Cloudflare check and cannot be read by the script: open the page and see
that the tool list matches.
Where it is listed, and how to take it down
The namespace is GitHub (io.github.flogvit/…), not DNS (com.flogvit/…):
flogvit.com's DNS is edited by hand at Domeneshop, and a GitHub login is
something a script can do.
The three that are not submitted need nothing but the login: the address, the
description and every field Anthropic's form asks for (one-liner, description,
documentation and privacy URLs, support contact, use cases, example prompts)
are written out in issue #157.
What each one got, and when, is in issue #157 on GitHub.
The guide page is /mcp in ../src/routes/pages/mcp.tsx. Removing it means
removing the route, the footer link in ../src/views/layout.tsx, /mcp in
../src/lib/sitemap-paths.ts and test/pages.ts, and the pointer in
llms.txt (../src/routes/seo.ts) — then deploying bibel.
Run it locally
Needs the local database the site uses (../.env, DB_PORT=3326).
Try it with the MCP Inspector (npx @modelcontextprotocol/inspector, transport
Streamable HTTP, URL http://localhost:8080/mcp), or by hand:
GET /healthz checks that the database user can read every content table and
reads John 3:16: 200 with the verse, or 503 with the reason — a missing grant is
named.
Tests
test/server.test.ts calls every tool over HTTP against the local database and
checks that each answer links only to localised pages on bible.flogvit.com (or
the sources the licence names) and never shows the site's [ref:…] markup.
test/grants.test.ts creates a local MySQL user with exactly the grants the
server gets in production, runs every tool as that user, and checks that the
user tables refuse it — a tool that needs a table outside the grants fails
there — and that /healthz names a table whose grant is revoked. test/books.test.ts checks that every book name and abbreviation the
site shows, in every language, finds its own book. test/find-references.test.ts
finds every book by every name inside a sentence, and its last verse as the
last. test/cli.test.ts runs the command line client (../cli/) as its own
program, with node and bun, against a listening server.
test/lookups.test.ts holds the six direct lookups to every row of their
tables. test/mapping.test.ts holds mapping to mapChapter() over every
chapter where the King James numbering differs from osnb, plus Malachi 4,
cross-references in and out, and check_references.
test/tool-quality.test.ts reads tools/list and fails on a tool without a
title, a description or all four annotation hints, an argument or output field
without a description, an optional argument that does not say its default, or
an allowed value its description does not name — what a client, and mcptry.com's
Tool quality score, read before calling anything.
bibel's own bun test in the repo root does not run these (bunfig.toml):
this package has its own dependencies.
How it is built
- Its own package, its own image.
@modelcontextprotocol/sdk and its
dependencies live here and never reach the site's image. The image is built
from the repo root (docker build -f mcp/Dockerfile .) because the server
reads the database through the site's own getters in src/lib/ — an answer
here is the page there.
- The image carries the vendored
@free-bible/kvn (kvn-package/, 109 MB
of mapping files), for the verse numberings. Stage it first —
bun run oppsett in bibel, which bibel's deploy does before it builds — or
the build stops at the COPY. test/image.test.ts follows every import from
src/index.ts and fails when the image would lack a file or a package; the
tests themselves cannot see it, since they resolve through bibel's own
node_modules.
- Its own database user, read-only on content.
src/grants.ts grants
SELECT on the tables the import owns (CONTENT_TABLES) and nothing else, so
users' notes, manuscripts and shares are out of reach.
- Stateless. One MCP server per request; any request can land on any
process.
- A global cap, not a per-IP one. Claude and ChatGPT call connectors from
their own servers, so one IP is many users. Over the cap the server answers
503 with
Retry-After instead of queueing without end. The command line
client is the one caller it can tell apart, and the one most likely to come in
a loop, so it may hold only MCP_MAX_CONCURRENT_CLI of the slots.
Configuration
bun scripts/grants.ts <database> prints the GRANT statements for the
database user. They are derived from CONTENT_TABLES, but applied only when
someone runs them: when the import gets a new content table, run them again as
the database admin. Until then /healthz answers 503 and names the table.