Skip to main content
Glama
0xJRP

spreadsheet-qa-kit MCP server

by 0xJRP

spreadsheet-qa-kit

Ask your spreadsheet a question in plain words. Get the answer - and the exact steps used to compute it.

Point it at a CSV (or an exported Google Sheet) and ask the kind of thing you'd otherwise build a pivot table for:

"What was total revenue in Q3 for the West region?"

…and the kit answers it, shows its work (which rows it filtered, which column it summed, how), and draws a simple chart when the answer breaks down by category. It reads your data - it does not edit it.

The trick: Claude never computes the number. Claude only translates your question into a concrete plan (filter region = West and quarter = Q3, then sum revenue). A small, auditable Node engine runs that plan over your real rows. So the math is plain code you can read, not model output you have to trust.

This is a real, runnable, MIT-licensed kit. No paywall, no neutered features. Run it on your own machine.


Quickstart

git clone https://github.com/0xJRP/spreadsheet-qa-kit.git
cd spreadsheet-qa-kit
npm install
npm run setup     # friendly wizard: Claude API key + path to your CSV
npm run dryrun    # answers a sample question from the bundled data and SENDS NOTHING

npm run dryrun loads the bundled sample spreadsheet, calls Claude to plan a sample question, runs that plan over the data, prints the answer with its work shown, renders a printable HTML report into out/, and shows exactly what an emailed report would contain - then sends nothing. It's the safest way to see the whole pipeline end to end. (It needs ANTHROPIC_API_KEY set, since it actually calls Claude.)

When you're ready to ask your own questions:

npm run ask -- "What was total revenue in Q3 for the West region?"
npm run ask -- "How many units did each rep sell? Show me a chart."
echo "total revenue by quarter" | xargs -0 -I{} npm run ask -- "{}"

Open the rendered report in out/ and print to PDF (Cmd/Ctrl-P → Save as PDF) to get a PDF.


Related MCP server: querywise-mcp

What it does

   Question                Claude brain              Your output
  ┌──────────┐   ───▶   ┌────────────────┐   ───▶   ┌──────────────────┐
  │ "Q3 sales│          │ a QUERY PLAN:  │          │ the answer +     │
  │  in the  │          │ filter + group │          │ the steps used   │
  │  West?"  │          │ + aggregate    │          │ + a simple chart │
  └──────────┘          └────────────────┘          └──────────────────┘
   Telegram / CLI / MCP   (NOT the answer)            engine runs the plan
                          over YOUR real rows         locally, shows its work
  1. A question. Type it on the CLI, or text it to a Telegram bot (npm start). Plain English, the way you'd ask a coworker.

  2. A brain. Claude reads the question and the spreadsheet's schema (column names, which are numeric, a few sample values) and returns a structured query plan - which rows to filter, whether to group, what to aggregate. Claude is told the exact column names and may only use those.

  3. A deterministic engine. src/sheet.js validates that plan against the real columns and runs it over your rows in plain Node code: filter, group, sum/average/min/max/count. It builds a step-by-step trace as it goes. This is where the number comes from - not the model.

  4. The answer, with its work. You get the headline answer, the steps ("Filtered 30 rows → 4 where region eq West AND quarter eq Q3. Computed sum of revenue over 4 rows = 18753."), an optional ASCII bar chart for grouped answers, and any assumptions Claude made (e.g. how it read "Q3"). All rendered to a clean HTML report you can print to PDF.

Your data is yours, and read-only

data/sample-sales.csv ships so the dry run works out of the box. Point DATA_PATH at your own CSV (or set GOOGLE_SHEET_CSV_URL to a published Google Sheets CSV link and pass --remote). The kit only reads that file. There is no write-back path anywhere in the code: it can answer questions about your data, never change it.

The spreadsheet as an MCP tool

The sheet is also exposed as an MCP server (npm run mcp, built on the official @modelcontextprotocol/sdk). It offers three read-only tools - sheet_schema, sheet_sample, sheet_query - so any MCP-aware client (Claude Desktop, an agent) can inspect and query your spreadsheet as a tool. sheet_query takes the same structured plan and returns the value plus the computation trace, so even an external agent gets the math from the engine, not from a guess.


The safety model - read-only / draft-first

This kit is read-only by design, with a draft-first email path. That's the whole point, and it's Rabbithole's trust differentiator.

  • Your spreadsheet is never edited. There is no write-back code. The kit loads the file, computes from it, and leaves it byte-for-byte unchanged.

  • The answer is auditable. Claude proposes the plan; the kit runs it and prints every step. You can check the filter and the arithmetic yourself - the engine is a few hundred lines of plain code.

  • The model can't invent a column or a number. Every column the plan references is validated against your real header row before anything runs. A bad column name is rejected with a clear error, not silently guessed.

  • Two locks guard the one optional send. Emailing a report happens only when (1) DRY_RUN=false in your .env and (2) you type yes to the confirmation. DRY_RUN defaults to true on a fresh checkout - a hard kill switch that makes every send path a no-op until you deliberately turn it off.

  • Money is never moved. There is no payment code of any kind.

Path

What guards it

Answer a question (Claude call + engine)

Local; reads your data, writes nothing to it

Render an HTML report

Local file write to out/

Draw a chart

Local, in-memory text

Email a report

DRY_RUN=false and typed yes confirmation

Edit / write back to the spreadsheet

Not implemented - by design

Charge a card / take payment

Not implemented - by design

CI / demos stay safe automatically: with DRY_RUN=true (the default), npm run dryrun runs the whole pipeline and provably sends nothing.


Configuration

Run npm run setup, or copy .env.example to .env and fill it in. Every value can also be supplied as a real environment variable, so npm run dryrun works non-interactively in CI:

ANTHROPIC_API_KEY=sk-ant-... npm run dryrun

Key settings (see .env.example for all of them, with comments):

Variable

What it's for

ANTHROPIC_API_KEY

Your Claude API key (from console.anthropic.com)

ANTHROPIC_MODEL

Defaults to claude-opus-4-8. For high-volume use, claude-haiku-4-5 is cheaper and faster

DATA_PATH

Path to your spreadsheet (CSV). Read-only

GOOGLE_SHEET_CSV_URL

Optional public Google Sheets CSV-export URL (use with --remote)

DRAW_CHART

Draw a simple text chart for grouped answers (true default)

SMTP_* / REPORT_TO

Email creds - only needed to actually email a finished report

TELEGRAM_BOT_TOKEN

Optional phone channel - ask questions by text

DRY_RUN

Global kill switch. true (default) = nothing can send

Which model?

The default is claude-opus-4-8 - the most capable Opus-tier model, great while you're dialing in the kinds of questions you ask. Once it's reliable and you're running high volume, set ANTHROPIC_MODEL=claude-haiku-4-5 for a cheaper, faster option. Turning a question into a filter/aggregate plan is a clean structured task, so Haiku handles it well.

Want an actual PDF (not just print-to-PDF)?

The kit renders self-contained HTML so there's no headless-browser binary to install. If you want a real .pdf generated automatically, add Puppeteer (npm i puppeteer) and render the HTML report to PDF - about ten lines. Print-to-PDF from any browser works today with zero extra setup.


How it's built

  • Runtime: Node.js, ES modules.

  • Brain: the official Anthropic SDK (@anthropic-ai/sdk) with structured outputs (messages.parse + zodOutputFormat) so the query plan comes back as a typed object. Model defaults to claude-opus-4-8.

  • Engine: plain Node - filter, group, aggregate, with a step-by-step trace. The model never produces the final number.

  • Tools: the official MCP SDK (@modelcontextprotocol/sdk) exposes the spreadsheet as read-only tools.

  • Email: nodemailer (only used when you turn sending on).

  • Inbound: Telegram long-polling over fetch - no extra dependency.

src/
  config.js        # loads .env (and real env vars) into typed config
  sheet.js         # load a CSV (or fetched Google Sheet) + run a query plan (the engine)
  query-engine.js  # the Claude brain - turns a question into a structured query plan
  render.js        # answer → printable HTML report + ASCII chart + a "show your work" text
  mailer.js        # the only send path; gated behind DRY_RUN + confirmation
  pipeline.js      # question → plan → computed answer → rendered report (sends nothing)
  cli.js           # dryrun / ask commands (confirm-before-send on --email)
  setup.js         # the first-run wizard (writes .env, points at your data)
  mcp-server.js    # MCP server exposing the spreadsheet as read-only tools
  server.js        # Telegram inbound - replies to YOU with the answer + its work
data/
  sample-sales.csv       # sample spreadsheet the dry run uses (point DATA_PATH at yours)
  sample-questions.txt    # example questions

DIY, or have us run it

You just got a complete, working spreadsheet-question-answering tool for free. Run it yourself - that's the whole idea.

When you're ready for the production version, that's where we come in. Rabbithole wires this to your real tools and runs it for your team: your live Google Sheets and databases (not just CSVs), richer charts, scheduled reports, multi-sheet joins, role-based access, and guardrails tuned to how your team actually asks questions of its data.

You can run this yourself - or we'll build the production version for your whole team. → rabbithole.consulting


License

MIT © 2026 Rabbithole Consulting. See LICENSE. Use it, fork it, ship it.

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/0xJRP/spreadsheet-qa-kit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server