The MCP server, completely
This page shows you how to let an AI assistant (like Claude Code or Cursor) actually use Lemma. It’s the most important “how to plug it in” page, and we explain every term from scratch.
The big picture
Your AI assistant is good at writing things but knows no guaranteed science. The Lemma MCP server is a little program that gives the assistant new buttons to press — buttons that look things up in the cards and check work against them. You install it once, switch it on, and from then on the assistant can press those buttons whenever it needs to.
flowchart LR
subgraph Runtime["Your AI assistant (Claude Code / Cursor / …)"]
Model[the AI]
end
Model <-->|presses buttons / gets answers| MCP["Lemma MCP server"]
MCP --> Engine[the checker]
MCP --> Corpus[(the cards)]
MCP --> RAG[(optional: a search database)]
classDef c fill:#1e3a5f,stroke:#4a90d9,color:#fff;
class MCP c;
Step 1 — install it
You need Node.js installed (the runtime that runs
JavaScript programs; if you can run npx, you have it). Then:
npx @artano-ai/mcp-serverThis downloads and starts the server. It will sit there quietly waiting — that’s
normal. You won’t usually run it by hand; instead you tell your assistant to
launch it for you, which is the next step. (Press Ctrl-C to stop it.)
Step 2 — switch it on in your assistant
You “register” the server — meaning you tell your assistant where to find it — by
adding a few lines to a settings file. For Claude Code the file is
~/.claude.json; for Cursor it’s ~/.cursor/mcp.json. (The ~ means your
home folder.) Add this:
{ "mcpServers": { "lemma": { "command": "npx", "args": ["@artano-ai/mcp-server"] } }}In plain words: “there’s a tool server called lemma; to start it, run
npx @artano-ai/mcp-server.” Restart your assistant and it can now use Lemma.
Want Lemma to use your own set of cards instead of the built-in ones? Add a
setting that points to your folder (LEMMA_CARDS_DIR is just the name of that
setting):
{ "mcpServers": { "lemma": { "command": "npx", "args": ["@artano-ai/mcp-server"], "env": { "LEMMA_CARDS_DIR": "/full/path/to/your/cards" } } }}The buttons (tools)
The server gives the assistant nine tools. Here’s the whole set at a glance:
| Tool | What you give it | What you get back | When it’s used |
|---|---|---|---|
cards_list | (nothing, or a topic) | a list of available cards | to see what’s in the library |
cards_get | a card’s id (name) | the full card | to read one card in detail |
ops_get | an “ops” card’s id | a ready-to-read template | to get a script/job template |
hypothesis_crosscheck | a proposed formula | a verdict (is it OK?) | to check a proposed formula |
usce_check | a finished result + a card id | a verdict (in range?) | to check a finished number against the card’s bounds |
series_check | a whole curve or spectrum + a card id | a verdict (any point out of bounds?) | when the answer is a series, not one number |
convergence_check | a refinement study + a card id | a verdict (does it converge as claimed?) | to check how fast a method converges, measured rather than asserted |
agreement_check | results from two or more methods | a verdict (do they agree?) | to check independent methods against each other |
rag_lookup | a question | relevant documentation passages | to search technical docs |
The middle five are all “check a finished result”, but against different kinds
of evidence. usce_check bounds one number. series_check bounds every
point of a curve — and reaches cards the others cannot, because some
quantities have no meaningful range at all yet still can never go negative.
convergence_check measures a rate from the data instead of taking your
word for it. agreement_check compares two methods rather than one result
against a bound.
A typical session looks like this — the assistant browses, reads, then checks its own work:
sequenceDiagram participant M as AI assistant participant S as Lemma server M->>S: cards_list (topic: chemistry) S-->>M: here are the chemistry cards M->>S: cards_get (id: arrhenius-rate-law) S-->>M: the full card (formula, notes, limits) Note over M: writes code using that card M->>S: hypothesis_crosscheck (the formula it wrote) S-->>M: verdict — if red, fix it and retry
Now each button in detail. (An “id” is just a card’s short name, like
arrhenius-rate-law.)
cards_list — see what’s available
You give it: optionally a topic word to filter by (like chemistry), or
nothing to see everything.
You get back: a tidy list, grouped by topic — each card’s id, title, and a
one-line summary.
The assistant asks for it like this (this is JSON — labels and values):
{ "name": "cards_list", "arguments": { "domain": "chemistry" } }And gets back (shortened — this is real output):
## chemistry-kinetics — 1 card- arrhenius-rate-law v1.0.0 — Arrhenius temperature dependence of rate constants## chemistry-thermodynamics — 1 card- ideal-gas-law v1.0.0 — Ideal gas lawcards_get — read one card fully
You give it: a card’s id. You get back: the complete card.
{ "name": "cards_get", "arguments": { "id": "arrhenius-rate-law" } }Returns the full record — the formula, what each symbol means, how it should behave in extreme cases, and references.
ops_get — get a ready-made template
Some cards (called ops cards) aren’t physics formulas — they’re reusable
templates for common chores, like a script to submit a job to a supercomputer.
ops_get returns one as clean, readable text. The three available today are
slurm-marenostrum5-gpp-compute, snakemake-dft-workflow, and
singularity-scientific-container.
{ "name": "ops_get", "arguments": { "id": "slurm-marenostrum5-gpp-compute" } }hypothesis_crosscheck — check a proposed formula
This is the star button. You give it a proposed formula (either the id of one already in the library, or a brand-new one written out in full). You get back a verdict: does it hold up?
Checking one that’s already in the library:
{ "name": "hypothesis_crosscheck", "arguments": { "id": "free-fall-with-linear-drag" } }Real reply (shortened):
Cross-check verdict — Free fall with linear (Stokes) air dragOverall: 3 of 6 checks passed · severity LOW- OK the units match (worked out from the formula itself)- OK every formula it refers to really exists- note three claims are recorded but not yet proven (this is expected here)Note what the “3 of 6” is not saying. Three checks passed; the other
three came back yellow — two limit claims and one conservation claim
that the server records rather than tests. None of them failed. A
yellow is the engine declining to answer, not a negative verdict, and
that is why the overall severity is LOW rather than HIGH.
Those three are dischargeable today, but not here: it takes the
Python SDK with symbolic=True,
which the MCP server does not have.
The really useful case is checking a brand-new formula the AI just invented.
The assistant sends the whole formula; Lemma works out the units from the
formula and checks them. A correct “energy of a moving object” formula comes
back green (looks correct). A wrong version (where the units don’t add up)
comes back red (serious problem) with an explanation. The
engine page shows exactly how that works.
usce_check — check a finished result
hypothesis_crosscheck vets a proposed formula. usce_check vets a finished
result. You give it a card id and an output (a map of value-name to
number); you get back a verdict: do the numbers fall within the bounds the
card declares?
{ "name": "usce_check", "arguments": { "id": "ideal-gas-law", "output": { "gasConstant_J_per_molK": 8.3145 }} }A value inside the card’s range comes back green; outside (say 9.0) comes
back red. v1 checks the card’s numeric ranges (“validation envelopes”);
checking trends over time (does it settle? does cause precede effect?) is on the
roadmap.
rag_lookup — search the technical docs
You give it a question; you get back the most relevant passages from a library of technical documentation — your library. This one is different from the other eight in two ways.
It searches documents you supply. No documentation ships with Lemma. You point it at your own — a code manual, a group’s internal notes, whatever your work actually depends on — and it indexes that.
It needs a database. Specifically Postgres with the pgvector add-on, plus a small AI model that turns text into numbers so similar passages can be found. Set it up with:
LEMMA_RAG_DSN=postgresql://user@localhost:5432/yourdb # where the database isLEMMA_RAG_SCHEMA=yourschema # which section of itLEMMA_EMBEDDING_PROVIDER=transformers # how to do the searchThen fill it, using the lemma-rag command that comes with the server:
lemma-rag init # prepare the databaselemma-rag ingest ./docs # read your documents into itlemma-rag status # see what is in thereUntil you do that, the tool has nothing to search — and it will say so rather than returning nothing, which would look like “no such thing exists” when the truth is “I have not been given anything to look in”.
If you don’t set up that database, the other eight buttons still work perfectly —
only rag_lookup is unavailable.
Settings reference
These “environment variables” are just named settings you can pass to the server:
| Setting | What it’s for | Needed for |
|---|---|---|
LEMMA_CARDS_DIR | use your own folder of cards | a private/custom card library |
LEMMA_RAG_DSN | where the search database lives | rag_lookup |
LEMMA_RAG_SCHEMA | which part of that database | rag_lookup |
LEMMA_EMBEDDING_* | how the search works | rag_lookup |
Set nothing and you get the built-in cards and the eight non-search tools.
If something’s not working
- The assistant never uses Lemma. Did you restart the assistant after
editing the settings file? Does
npx @artano-ai/mcp-serverstart on its own (it should sit quietly waiting)? - “unknown card id” errors. That’s on purpose — run
cards_listfirst to see the real ids; the error lists them. rag_lookupis missing or errors. It needs the database described above. The other tools don’t.- Wrong cards showing up. Check the
LEMMA_CARDS_DIRsetting — if it’s not set, you get the built-in library.
Next
- The engine, completely — what the verdicts actually mean.
- Cards, completely — the records these buttons serve up.
- The Python SDK — the same powers, from Python code.