Skip to content

Get started in 5 minutes

Four steps: get a key, connect your agent, load your data, ask.

1. Get a key

Open api.limma.ai/v1/billing/checkout?plan=free and sign up — the Free plan takes no card and costs nothing, for as long as you use it (50 documents, 250 pages a month); move to a paid plan in place whenever you need more (plans and limits). When checkout is done, the welcome page shows your key once: copy it then. It is an admin key for your organization, so keep it out of files you commit and out of chat.

Put it in your shell — Claude Code, Cursor and the limma command read it from there:

export LIMMA_API_KEY=<your key>

2. Connect your agent

One setup per client. Claude Code and Cursor read the key from LIMMA_API_KEY, so it is not written into a file you might commit; VS Code asks for it once and stores it; Claude Desktop keeps it in its own configuration file.

Claude Code — one command:

claude mcp add --transport http limma https://api.limma.ai/mcp --header 'X-API-Key: ${LIMMA_API_KEY}'

Keep the single quotes: Claude Code expands ${LIMMA_API_KEY} itself each time it connects.

Cursor — .cursor/mcp.json in the project (or ~/.cursor/mcp.json for every project):

{
  "mcpServers": {
    "limma": {
      "url": "https://api.limma.ai/mcp",
      "headers": {"X-API-Key": "${env:LIMMA_API_KEY}"}
    }
  }
}

VS Code (agent mode) — .vscode/mcp.json; VS Code asks for the key once and stores it:

{
  "inputs": [
    {"type": "promptString", "id": "limma-api-key", "description": "Limma API key",
     "password": true}
  ],
  "servers": {
    "limma": {
      "type": "http",
      "url": "https://api.limma.ai/mcp",
      "headers": {"X-API-Key": "${input:limma-api-key}"}
    }
  }
}

Claude Desktop — its claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), through mcp-remote, which needs Node.js. The key is in this file in plain text, so keep it to your machine:

{
  "mcpServers": {
    "limma": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.limma.ai/mcp",
               "--header", "X-API-Key:${LIMMA_API_KEY}"],
      "env": {"LIMMA_API_KEY": "<your key>"}
    }
  }
}

Any other MCP client — the URL https://api.limma.ai/mcp, transport "streamable HTTP", and the header X-API-Key: <your key> (or a bearer token holding the key).

Your agent now has six tools: limma_search, limma_facts, limma_region, limma_ingest, limma_connect and limma_documents (the documents it may read, and how completely each was read). You never create a workspace: a call that names none uses your organization's default one. More on the endpoint: MCP over HTTP.

3. Load your data

Three ways, all into the same workspace:

  • A folder — the limma command keeps a workspace equal to a folder. Run it again and only what changed is sent:

    pip install limma-ai
    read -rs LIMMA_API_KEY && export LIMMA_API_KEY      # paste your key; nothing is echoed
    limma sync ./my-documents --url https://api.limma.ai
    

    The same command reads an S3, Azure Blob or Google Cloud Storage bucket, a Google Drive folder and a SharePoint library (connectors).

  • From your agent — ask it: "Upload ./report.pdf to Limma." It asks limma_ingest for a one-time upload link and runs the command it is given; nothing else is needed (files from an agent).

  • An export of records — a CSV, JSON or Excel file, each row loaded as a record (what you can connect).

Each document is read in the background. limma_ingest waits for the read (45 seconds unless it asks for another wait, at most 120); a longer document is still read after the call returns, and asking again tells your agent where it is.

4. Ask

Ask your agent in plain words. Three prompts to start with:

  1. "What revenue does Acme report for each year? Cite the page for each number."
  2. "Which of our contracts renew before March? Is that every one?"
  3. "Do any of our documents disagree about headcount?"

What comes back to the agent is not a passage to guess from. For the first prompt it is every revenue figure Limma holds for Acme — each with the value as printed, its period, the document, the page and the characters it sits at — and a count of how many exist. This is the reply the agent reads (run against a test workspace holding a small annual report and a restated quarterly update — how the examples work):

import json
MCP = {"Accept": "application/json, text/event-stream"}
r = client.post("/mcp", headers=MCP, json={
    "jsonrpc": "2.0", "id": 1, "method": "tools/call",
    "params": {"name": "limma_facts", "arguments": {
        "workspace_id": WS, "question": "Acme revenue", "mode": "enumerate",
        "coordinate": {"attribute": "revenue"}, "output_mode": "compact"}}})
reply = json.loads(r.json()["result"]["content"][0]["text"])
count = reply["enumeration"]
print("exist:", count["exist"], "| delivered:", count["delivered"], "| truncated:", count["truncated"])
for fact in sorted(reply["facts"], key=lambda f: f["period"]):
    print(fact["entity"], fact["period"], fact["value_token"], "| page", fact["page"],
          "| characters", fact["char_start"], "to", fact["char_end"],
          "| checked:", fact["byte_verified"], "| contested:", fact["contested"])
exist: 3 | delivered: 3 | truncated: False
Acme Corp FY2022 1,100 | page 0 | characters 135 to 140 | checked: True | contested: False
Acme Corp FY2023 1,250 | page 0 | characters 126 to 131 | checked: True | contested: False
Acme Corp Q1 2024 312 | page 0 | characters 52 to 55 | checked: True | contested: False

  • exist and delivered — how many facts exist at the address, and how many came back. When they differ, truncated is true and the agent knows to ask for the rest (a count).
  • checked: True (byte_verified) — Limma read those characters of the page again and they print exactly that value. The agent can read them itself with limma_region (a receipt).
  • contested — when two places disagree, both values come back marked contested, each with its own source, and Limma does not pick one (contested). The third prompt gets exactly that.

For the second prompt, limma_search returns the whole set of matches, the sentence behind each, the near misses listed apart, and whether the set is complete — and when it is not, why (search).

Next: what you can connect · security and your data · questions people ask · all guides