Skip to main content
Glama

Landmark

An MCP server that lets you ask a spreadsheet questions out loud, instead of walking it cell by cell.

Built for the Alexa+ track of the Amazon Developer Hackathon 2026. MIT licensed. Spec revision 2025-11-25 over Streamable HTTP, self-hosted.


The problem, stated accurately

It is tempting to write "screen readers lose header context." That is not true, and getting it wrong would be the fastest way to lose the trust of anyone who actually uses one. JAWS and NVDA both announce headers in Excel.

The real difficulty is narrower and harder:

  • Header association is manual, per worksheet, and does not travel. Headers set up for one reader do not carry to another — NVDA #11801, open since November 2020, is about exactly that.

  • Most files never declare structure at all. The WebAIM Million, February 2026 observed 948,225 tables and found valid data-table markup on 19% of them. Section508.gov puts it plainly: "Excel does not provide tools to make complex tables accessible."

  • Even with headers announced, questions cost traversal. "What is the total?" is O(rows). "Which region did best?" is O(rows × cols). There is no cheap way to learn a table's shape before committing to walking it.

A sighted reader answers all three with a glance, which costs nothing and is not sequential. Landmark reconstructs the structure the file never declared, so the same questions can be asked rather than traversed.

Related MCP server: mcp-excel

What it does

"What's in the budget file?"
   → "FY2026 Departmental Budget has 5 rows and 3 columns. The columns are
      Department, Line item and Amount. 3 cells take their label from a merged
      block, so they are not the blanks they look like."

"Total for Engineering?"
   → "560 thousand. That is the total of Amount across 3 rows."

"How do you know?"
   → "That came from C3 through C5 on Budget. Each one is Amount."

The third exchange is the one that matters. CHI 2026 research on blind spreadsheet users found they never fully trust an AI-produced number they cannot verify — and over audio there is no cell to glance at. So every answer carries the cells it was computed from, and table_explain reads them back.

Why this is not a basic MCP wrapper

The Alexa+ track rules name "a basic MCP wrapper around an existing API" as the obvious shape of entry, against a creative list that includes cross-session state, autonomous orchestration and MCP Apps. That is a fair challenge to put to a project shaped like this one, so here is the answer in specifics.

1. It infers structure that is not in the file. A spreadsheet declares a grid, not a table. Landmark detects table regions separated by blank rows, scores which rows are headers and reports its confidence rather than guessing silently, resolves merged blocks, and reconstructs a full header path for every column. Four columns all labelled Revenue come back as 2026, Q1, Revenue2025, Q2, Revenue. There is no API to wrap here — this is the work.

2. Provenance is a protocol affordance, not a log line. Every aggregate records its source cells, the rows it excluded, and why. Nothing is recomputed on explain, because a recomputation that disagreed with what was already spoken would be worse than no provenance at all. Excluded rows are said out loud: "the total across 47 of the 52 rows; five were empty" is a different claim from "the total".

3. The result-size governance is in the server, not the prompt. Every tool returns a spoken field inside a word budget, capped at five items with a continuation token, with numbers scaled for listening and identifiers stripped. A voice product whose brevity depends on the model remembering to be brief is a chatbot that happens to be read aloud.

4. State survives the session. table_bookmark and table_resume keep a place in a long table across days, backed by KV rather than conversation history, and re-orient before reading — because the user may not have been here for a week.

5. It orchestrates across sheets. table_compare runs two aggregations in different regions or different files and returns the difference and its direction in one sentence, so nobody has to hold two numbers in their head and subtract them.

And what it deliberately does not do: there is no get_cell, get_row or get_column. Those would rebuild the cell-by-cell maze in tool form and hand the traversal problem back to the model.

Prior art, conceded

The intersection is unoccupied; none of the neighbourhoods are.

~50 spreadsheet MCP servers exist in the official registry (excel-mcp-server has 4,000+ stars and already speaks Streamable HTTP)

They exist to save an LLM tokens. Their consumer is a developer. None mention accessibility, blind users, voice or speech.

VoxLens (CHI 2022) and VERSE (ASSETS 2019) did voice and sonified access to data for screen-reader users years ago

Both require the data's publisher to instrument the content. An MCP server inverts that: the user brings their own file and needs nobody's cooperation.

Copilot in Excel works with a screen reader today

It documents a prerequisite of AutoSave and OneDrive. It does not help with a CSV someone emailed you, and it returns a chat pane you must then navigate.

The one checkable claim, and reproducible by anyone: as of 2026-09-08 the official MCP registry's accessibility servers are all axe/WCAG auditing tools built for sighted developers. Query registry.modelcontextprotocol.io for accessibility and read the descriptions. There is no assistive MCP server whose consumer is a disabled end user.

Run it

npm install
npm run fixtures                                   # generate the sample spreadsheets
npm run ingest -- test/fixtures/*.xlsx test/fixtures/*.csv
npm run serve                                      # http://localhost:8787/mcp

A demo index ships in data/index.json, so npm run serve works immediately after npm install. Point any MCP client at http://localhost:8787/mcp; GET /health reports the negotiated protocol revision and the corpus size.

npm test          # 60 tests
npm run typecheck # strict, noUncheckedIndexedAccess, exactOptionalPropertyTypes
npm run demo      # prints what the voice agent actually says

How it is put together

spreadsheet ──[ ingest CLI, Node ]──▶ data/index.json ──[ Worker ]──▶ MCP tools

The split is forced and useful. ExcelJS needs Node streams and Buffer, which Cloudflare Workers do not have. Rather than shim it, everything expensive happens once, offline, and the server does pure computation over plain JSON — which is what keeps a grouped aggregate over 2,000 rows at p95 under 5 ms against a 500 ms budget, with no cold start to pay because V8 isolates do not have one.

Path

What lives there

src/table/

Region detection, header scoring, merge resolution, header paths, type inference

src/ingest/

Readers for xlsx/csv/tsv and the index builder — Node only

src/query/

Deterministic filtering and aggregation, with exclusion accounting

src/voice/

Spoken formatting, word budgets, number scaling

src/mcp/

The eight tools and the answer/bookmark store

src/server.ts

Web-standard fetch handler — the same code locally and on Workers

The eight tools

Tool

For

table_list

What files are available

table_describe

Orientation: shape, columns, types, gaps — call it first

table_query

Filter and aggregate; returns a spoken sentence plus provenance

table_explain

Read back the exact cells behind a previous answer

table_read_rows

Individual rows, five at a time, when a summary will not do

table_compare

Two measures, across columns, sheets or files

table_bookmark

Save a place

table_resume

Come back to it, re-oriented

Status and honest limits

  • Header detection is heuristic and says so. Where confidence is low the server tells the user out loud rather than guessing silently — an audible "I could not find a header row, so I am calling the columns by position" is both better engineering and better accessibility than a confident wrong answer nobody can spot.

  • Alexa+ device integration is not possible for anyone outside Amazon's partner program: the MCP Toolkit is documented as "available to select partners only" and "available in the United States". The MCP server is the deliverable the track asks for; the accompanying voice client stands in for device access.

  • No blind co-designer yet. Every study cited above ran with 12–99 participants; this has run with none, and that gap is real. A feedback session is being arranged and will be credited here by name.

Licence

MIT — see LICENSE. Dependency audit notes are in docs/SECURITY-NOTES.md; the two moderate advisories npm audit reports are analysed rather than suppressed.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables users to ask questions about their spreadsheets in plain English and receive instant answers using DuckDB-powered analytics, supporting multiple file formats like Excel, CSV, and Parquet.
    2
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables querying Excel and CSV files using SQL via natural language, allowing AI assistants to analyze data without manual SQL writing.
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to query tabular data (CSV/TSV) using natural language with cell-level citations, supporting multi-tenant workspaces, access control, and semantic search.
    27
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables querying your spreadsheet using natural language questions; provides read-only tools for schema, sample data, and structured query execution with auditable computation traces.
    MIT