mova-serve
The public parse service of Mova at mova.elamur.ai/free/en/parse/: a page with a text box and shareable
addresses, an API (https://api.mova.elamur.ai/v1/parse, also /api/v1/parse on the site; documented at /free/en/parse/api/)
that answers in Markdown, JSON, JSONL, YAML or CoNLL-U, an MCP server (/v1/mcp on the API host, /api/v1/mcp on the site, and a stdio
transport), word quotas, and, Elamur-wide, the terms (https://elamur.ai/terms/), the privacy policy
(https://elamur.ai/privacy/) and the account (https://cabinet.elamur.ai/, sign-in with Google, callback https://elamur.ai/account/callback; one sign-in for every
subdomain of elamur.ai).
It runs mova-parse (level 1: the language, dialect and style of every sentence and span;
level 2: each language's own model, en.bin, fr.bin) and the pragmatics layer prag
(frames, the speech-act perceptron, implicatures, presuppositions, irony candidates) on every English sentence.
How it works
-
Hosts. One process serves four hosts by the
Hostheader:mova.elamur.ai(pages and/api/v1/…),api.mova.elamur.ai(the API at the root:/v1/parse,/v1/r/<id>.md,/v1/mcp,/v1/health; the origin is--api-originor$MOVA_API_ORIGIN),elamur.ai(/terms/,/privacy/and the Google callback/account/callbackonly) andcabinet.elamur.ai(the account:/,/signin,/callback,/keys, …;?return=goes back only to https addresses on elamur.ai). The old/free/en/parse/terms/and/free/en/parse/account/…redirect (301);/apiand/api/redirect to the API page. The session cookieelamur_sessionhasDomain=.elamur.ai,Secure,HttpOnly,SameSite=Lax.Originchecks accepthttps://elamur.aiandhttps://*.elamur.aionly. Terms versionelamur-2026-11-06: accounts that accepted an older one sign in again. -
Formats (
formats,md).format=md|json|jsonl|yaml|conllu, a suffix on a stored result (/v1/r/<id>.md, long texts only: they have a short id) or theAcceptheader; JSON by default. Markdown: title, per sentence language/dialect/style, token table, tree outline, frames, pragmatics, model SHA-256s, CoNLL-U in a fence (golden file Mova analysis: Can you pass the salt?, bless withMOVA_BLESS=1). MCP tools answer in Markdown by default and takeformat. The result page links the short link and the analysis in every format. -
Analysis (
engine). A text is normalised (line ends, runs of spaces, empty lines), parsed byDispatcher::parse(orparse_aswhen the reader picks the language), written as CoNLL-U, and the tokens of the answer are read back from that document, so the JSON and the download agree. English sentences go toprag::frames::frames_of_treewith one discourse context for the text,prag::inferandprag::irony; the speech act, form, indirectness, hedging, polarity and voice come fromprag::eval::Labeler, trained at start on a pragmatics silver run (--prag-silver). Deterministic: the same text, language and model versions give the same bytes; the model files' SHA-256 are in every answer and in the cache key. -
Pages (
html,svg). The tree is an inline SVG (arcs stacked by span, the hub's tree classes), with a table as its text alternative and a CoNLL-U download; frames and pragmatics in<details>sections; no script. The hub's header, menu, icons, stylesheet and footer come from a shell file written by the hub's generator (papers parse-shell), with the hub's release in it; without one a plain shell is used. -
Cache (
cache). W-TinyLFU (Einziger, Friedman & Manes 2017): a 1% window LRU, a segmented main LRU, admission by a count-min sketch of 4-bit counters halved every10 × widthaccesses. Bounded in bytes. The most valuable queries are written towarm.jsonland parsed again at start. -
Concurrency (
server). The models are loaded once and shared (Arc) by a fixed pool of workers behind a bounded queue; a full queue answers 503 withRetry-After, a slow parse 504. -
Limits (
quota,ratelimit). Words by Mova's tokenizer: anonymous 5 000 a request and 250 000 a day per IP address; a free account 20 000 and 1 000 000 a day; more tiers from--plans(no billing). Day counts persist inusage/<date>.jsonfor two days. A token bucket per client against bursts. -
Accounts (
auth). OpenID Connect authorization code flow with PKCE (S256); the ID token's RS256 signature is verified against Google's JWKS, withiss,aud,exp,nonceand a verified e-mail. Sessions and API keys are random tokens stored as SHA-256 hashes (a session only as a hash; a key also as an AES-256-GCM sealed copy bound to its account, with the secret inkeys.secretof the state directory, mode 600, apart fromoauth.env, so its owner can see it again in the cabinet and on the API and MCP pages:?key=<name>picks a key by name,nonethe placeholder; those pages are private when signed in); sign-in and keys record the terms version accepted and when. CSRF: HMAC tokens bound to the session, a double-submit cookie before it, theOriginheader checked. -
MCP (
mcp). Revisions 2025-03-26, 2025-06-18 and 2025-11-25 of the Model Context Protocol specification:initialize,ping,tools/list,tools/callwithparse_textandexplain_sentence; Streamable HTTP (JSON answers, 202 for notifications, no session id,Originchecked) and stdio (mova-serve mcp-stdio, which forwards to the HTTP endpoint with the key). Authentication is an account's API key, not the specification's OAuth 2.1 authorization. -
What is kept (
store). The request log (JSONL, one line per parse with the text; daily zstd archives, bounded in size, 90 days), a ring of the last 20 results, short links of long texts (at most 20 000, 90 days), the day's word counts by IP address and account (2 days), accounts until deleted. The terms page says the same.
Run
cargo build --release -p mova-serve
mova-serve serve --port 8495 --model en=$MOVA_DATA/en/models/en.bin --model fr=$MOVA_DATA/fr/models/fr.bin \
--prag-silver <silver run dir> --state <dir> [--shell shell.html] [--oauth oauth.env] [--plans plans.json]
mova-serve bench --model en=… --model fr=… --prag-silver <dir> latency, memory, determinism digest
mova-serve mcp-stdio --endpoint https://api.mova.elamur.ai/v1/mcp with ELAMUR_API_KEY set
Measurements
2026-11-06, mova-serve bench (one worker, through the API route, JSON included; en.bin, fr.bin, the
pragmatics perceptron on 2 986 silver sentences): models loaded in 7 s, 821 MB resident after loading, 836 MB peak.
| words | cold p50 ms | cold p95 ms | cached p50 ms | cached p95 ms | answer KB |
|---|---|---|---|---|---|
| 1 | 0.52 | 1.36 | 0.052 | 0.057 | 2.3 |
| 13 | 2.87 | 4.16 | 0.014 | 0.015 | 5.6 |
| 103 | 18.09 | 19.69 | 0.059 | 0.063 | 38.9 |
A 5 000-word text (the anonymous limit): 0.66 s cold, 8 ms cached, 1.9 MB of JSON. Two processes give the same digest of 19 fixed answers. The cache's negative control: with admission off (plain LRU) a one-off flood of 5 000 unique queries evicts all 20 popular entries; with W-TinyLFU it keeps all 20.
Limits
Frames and pragmatics are English only; French gives trees (fr.bin, experimental). The speech-act labels are the
perceptron's (measured 2026-09-26 on held-out silver: act 68.8% against a 33.3% majority baseline, form 94.1%); its
margins are scores, not probabilities. The expression lens of prag (Wiktionary meanings, CC BY-SA) is not shown.
The attachment of a switched span is a placeholder (CSAttach=root), as in mova-parse.
This page in Markdown → https://md.mova.elamur.ai/free/en/docs/tools/mova-serve/