Skip to content

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:

Terminal window
npx @artano-ai/mcp-server

This 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:

ToolWhat you give itWhat you get backWhen it’s used
cards_list(nothing, or a topic)a list of available cardsto see what’s in the library
cards_geta card’s id (name)the full cardto read one card in detail
ops_getan “ops” card’s ida ready-to-read templateto get a script/job template
hypothesis_crosschecka proposed formulaa verdict (is it OK?)to check a proposed formula
usce_checka finished result + a card ida verdict (in range?)to check a finished number against the card’s bounds
series_checka whole curve or spectrum + a card ida verdict (any point out of bounds?)when the answer is a series, not one number
convergence_checka refinement study + a card ida verdict (does it converge as claimed?)to check how fast a method converges, measured rather than asserted
agreement_checkresults from two or more methodsa verdict (do they agree?)to check independent methods against each other
rag_lookupa questionrelevant documentation passagesto 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 law

cards_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 drag
Overall: 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:

Terminal window
LEMMA_RAG_DSN=postgresql://user@localhost:5432/yourdb # where the database is
LEMMA_RAG_SCHEMA=yourschema # which section of it
LEMMA_EMBEDDING_PROVIDER=transformers # how to do the search

Then fill it, using the lemma-rag command that comes with the server:

Terminal window
lemma-rag init # prepare the database
lemma-rag ingest ./docs # read your documents into it
lemma-rag status # see what is in there

Until 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:

SettingWhat it’s forNeeded for
LEMMA_CARDS_DIRuse your own folder of cardsa private/custom card library
LEMMA_RAG_DSNwhere the search database livesrag_lookup
LEMMA_RAG_SCHEMAwhich part of that databaserag_lookup
LEMMA_EMBEDDING_*how the search worksrag_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-server start on its own (it should sit quietly waiting)?
  • “unknown card id” errors. That’s on purpose — run cards_list first to see the real ids; the error lists them.
  • rag_lookup is missing or errors. It needs the database described above. The other tools don’t.
  • Wrong cards showing up. Check the LEMMA_CARDS_DIR setting — if it’s not set, you get the built-in library.

Next