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 six buttons (tools)
The server gives the assistant six 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 output’s numbers against the card’s bounds |
rag_lookup | a question | relevant documentation passages | to search technical docs |
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 one claim is recorded but not yet fully proven (this is expected today)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.
This button is different: it needs a database to work (a place to store and search the documentation). Specifically a Postgres database with the pgvector add-on, plus a small AI model to do the searching. You turn it on with these settings:
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 searchIf you don’t set up that database, the other four 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 four 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.