Showboard

Your coding agent answers with dashboards: charts and tables from read-only SQL, Excel and CSV.

Documentation

Showboard

Ask in your terminal. Get a dashboard on your screen.

Showboard is an open-source MCP server that lets Claude Code, Codex, Cursor, Gemini CLI and other coding agents answer questions about your SQL database, or a folder of Excel and CSV files, with charts, tables and headline numbers: in your browser, inside your own app, or beside your terminal.

MCP server License: MIT Node.js 22.13 or later

Live demo  ·  Quick start  ·  How it works  ·  Benchmark  ·  Docs


Claude Code in a terminal beside Showboard's page in a browser. Asked for the best seller of 2026 and how it compares with last year, Claude calls Showboard's draw tool and a board appears: $462,088 of Aero Standing Desk revenue in 2026, $275,176 in the same months of 2025, 67.9% growth, a monthly revenue line, 2026 revenue by category and the top 5 products

2.7× cheaper  ·  3.5× fewer output tokens  ·  3.2× faster
Claude Code with Showboard against Claude Code on its own, on the same questions and the same files. See the benchmark

[!NOTE] Built with AI assistance. Showboard is developed with help from AI coding agents, mostly Claude Code. A test suite and a measured benchmark keep it honest. It is young, so issues and pull requests are welcome.

Why Showboard

Ask a coding agent for a chart of your data and watch what it does. It writes Python to read your files and work out the numbers, checks the results over several steps, then writes an HTML page, chart code and all. It gets there, but every answer is a small software project, paid for in tokens and minutes, and the numbers live in code you have to read to trust.

Showboard gives the agent a shorter path. The agent writes a few SQL queries and a short layout. Showboard runs the queries read-only, picks a chart for each result, lays out the board and puts it on your screen.

Claude Code on its ownClaude Code + Showboard
You getParagraphs, or an HTML file it wroteA board of charts, tables, headline numbers and notes
You see itIn the terminal, or in a file you openIn your browser, inside your app, or beside your terminal
The numbers come fromPython it wrote and ranRead-only SQL, one click away under every chart
24 answers, measured$4.77 and 24.3 minutes$1.78 and 7.5 minutes

Benchmark

Bar chart, lower is better. Cost: $4.77 for Claude Code alone against $1.78 with Showboard, 2.7× cheaper. Output tokens: 128,929 against 36,659, 3.5× fewer. Time: 24.3 minutes against 7.5, 3.2× faster

Five questions about the sample spreadsheets (one with a follow-up), each asked four times over two runs: 24 answers each way, in Claude Code with Opus 5.5 at medium effort. On its own, Claude worked the numbers out in Python, then wrote an HTML page of charts. With Showboard, it wrote SQL and a short layout.

  • 2.7× cheaper: $1.78 against $4.77, at API list price. On Pro and Max plans the same tokens count against your usage limit instead.
  • 3.5× fewer output tokens: 36,659 against 128,929, and 2.3× fewer new input tokens (99,200 against 231,443).
  • 3.2× faster: 7.5 minutes against 24.3.
  • Cheaper on all 24 answers, by 1.6× to 4.4×, with the same figures both ways.

Most of what an answer costs is steps, because each step re-reads the whole conversation. On its own, Claude writes the analysis as code, checks it over several turns, then writes the page. With Showboard, a board is one call, and a board worth repeating becomes a recipe. In the demo shop, at API list prices, "Top 5 products of 2025" was one recipe call ($0.26), and "Each channel's revenue by quarter, 2025 vs 2026" one draw call ($0.37) that saved itself as a recipe.

To be fair to the other side: the pages Claude wrote on its own were more designed, each made to measure, where Showboard's boards are plainer and consistent. This is two runs on one dataset, and other agents have not been measured yet. The questions, every turn's results and how to rerun it on your own files are in bench/.

Quick start

You need Node.js 22.13 or later and a coding agent. The demo uses Claude Code. Showboard is on npm as showboard.

Claude Code: install the plugin

At the prompt of a Claude Code terminal session:

/plugin install showboard --marketplace rohanbeingsocial/showboard

When it asks, set Data to a folder of spreadsheets, one spreadsheet or a SQLite file (or Database URL to a Postgres URL), then ask Claude about your data. Boards appear in a pane beside the chat and at http://localhost:4711, in every project. A project where you ran showboard init keeps its own. See plugins/claude-code.

Claude desktop app: install the extension

Download showboard-<version>.mcpb from the latest release and install it in Settings, Extensions, Advanced settings, Install Extension…. Pick your spreadsheet folder (or give a database) when it asks, and boards open at http://localhost:4712. No Node.js needed: the app brings its own. See plugins/claude-desktop.

Let your agent set it up

In your project, ask your coding agent:

Set up Showboard in this project: run npx showboard guide and follow it.

The guide (SETUP.md) has the agent pick the path that fits the project: spreadsheets, a database, or your own app (with server code for Next.js, Express, Hono and node:http). The agent then checks its own work with showboard doctor, which starts Showboard the way each agent will and says how to fix anything that fails.

Try the demo

A small furniture shop's admin app, with its orders in SQLite:

git clone https://github.com/rohanbeingsocial/showboard.git
cd showboard
npm install
npm run demo        # builds, seeds the shop's database and serves http://localhost:4710

Open http://localhost:4710, then start Claude Code in the demo's folder from a second terminal:

cd examples/sales-demo
claude              # the .mcp.json here connects Claude Code to the demo

Approve the folder's showboard server when Claude Code asks, then try:

  • "Show me my best seller of 2026, and how it compares with last year."
  • "Top 5 products of 2025." This one is a recipe the demo ships, so the board takes a single tool call.
  • "Open the Aero Standing Desk's orders from October." Claude runs the shop's own Orders filter.

Your spreadsheets

cd my-reports          # a folder of .xlsx, .xlsm, .csv or .tsv files
npx showboard init .   # Claude Code; --agent codex,cursor,gemini… for others
claude                 # then open http://localhost:4710, or run: npx showboard pane

Each sheet becomes a table the agent can query and join. Loading copes with the usual mess: title rows above the header, blank rows, "Total" rows (skipped, so sums do not double count), N/A in number columns, ₹1,23,456 and $1,234.50 typed as text, Excel dates, and 15-Mar-2026 or 25/04/2026 text dates. Amounts print in the files' own currency, ₹ in lakh and crore for rupee sheets. Your files are only read, and they reload when you save them. To try it on sample files: cd examples/spreadsheets, run claude and open http://localhost:4720.

A database, no app

npx showboard init --db ./shop.sqlite   # a SQLite file or a Postgres URL
claude                                  # boards appear at http://localhost:4710

A Postgres URL with a password is better kept out of the settings files: leave --db out, and set SHOWBOARD_DB in your environment before you start your agent.

Your own app

Mount Showboard in your Node server and React pages: see Put boards in your own app.

How it works

How a question becomes a board. You ask your agent (Claude Code, Codex, Cursor, Gemini CLI) a question. The agent sends SQL to Showboard over MCP. Showboard, on your computer, runs it read-only against your data (Postgres, SQLite, Excel, CSV) and gets rows back, picks the charts and sends the board live to your screen: a browser, your React app or a terminal pane. The rows also go back to the agent. You see the board, and every chart can show its SQL
  1. You ask your agent a question, like "Which regions are behind their 2026 targets?"
  2. The agent calls Showboard over MCP: a saved recipe if one fits, or draw with one SQL query per chart.
  3. Showboard draws the board. It runs each query read-only, picks a chart from the shape of each result and lays out the board.
  4. The board appears on your screen and joins the saved boards. The agent gets the rows back, so it can check what it tells you.

The agent never types a figure into a chart: every number comes from a query, and every chart can show its SQL. Think of Showboard as a pen for your agent, with two limits on purpose: in your app it draws only where you give it room, and it acts only through the actions you register, never by clicking around your screen.

For the full picture, with where each part lives in the code, see How Showboard works.

Excel and CSV, no app needed

Claude Code beside Showboard's page over a folder of Excel and CSV files. Asked which regions are behind their 2026 targets, Claude draws a board in rupees: actual against target by region, the gap to target for each region and the cumulative gap by month. Show sources then opens the SQL that joins the workbook's orders with the targets file

A folder of spreadsheets is all it needs. Here Claude Code compares 2026 orders in an Excel workbook with targets in a CSV file, amounts in rupees, and Show sources opens the SQL behind a chart.

In a real app

Claude Code in an investing app's folder beside Showboard's page. Asked whether silver went up each time the gold/silver ratio crossed above 90 in the past 2 years, Claude reads gold and silver prices from the app's API and draws a board: the ratio crossed above 90 four times, all in February and March 2025; silver was higher 6 months later all 4 times and 1 month later 3 times out of 4; the ratio is 70.7 today. Line charts of the ratio and of silver mark the stretches above 90, bars show silver's moves 1, 3 and 6 months after each cross, and a table lists each stretch

It works on real data too. Meridian, a private investing app, has Showboard inside. Here Claude Code is asked whether silver rose each time the gold/silver ratio crossed above 90. It reads two years of MCX gold and silver prices from the app's own API and draws one board: the ratio and silver side by side, each stretch above 90 marked in orange, and silver's moves 1, 3 and 6 months after each cross.

Inside your own app

Claude Code beside the demo shop's admin app. Asked to open the Aero Standing Desk's orders from October, Claude reads the app's screen with get_screen, then runs the app's filter_orders action, and the app moves from its board page to the Orders page, filtered to October 2026 and the Aero Standing Desk

Mount Showboard in your React app and the agent can also see what is on screen and run the actions you register. Here Claude reads the demo shop's screen with get_screen, then runs the shop's own filter_orders action, and the app opens its Orders page, filtered.

Beside your terminal

showboard pane in a terminal: a board titled Revenue by channel, 2025, with headline revenue and orders, a braille line chart per sales channel, block bars by category, a stacked share bar, a table of top products and a note

No browser needed: showboard pane draws each board as text in a terminal split beside your agent, and follows each new board as the agent draws it.

npx showboard pane                                         # Showboard on port 4710
npx showboard pane --url http://localhost:3000/showboard   # one your app mounts

Lines become braille, bars become blocks, shares become one stacked bar with a legend, and tables, notes and headline numbers print as they are, every figure read from the board's data. Keys: ← → older and newer boards, s sources, 1–9 the board's buttons (they run in your app), o the browser, q quit. --once prints the board and exits.

In Claude Code, the same view sits beside the chat: the plugin brings it along with a Showboard of its own. It opens by itself when a board arrives and the terminal has room, and /board opens it anywhere. Install it at the prompt of a Claude Code terminal session:

/plugin install showboard --marketplace rohanbeingsocial/showboard

Features

  • Read-only by design. Postgres queries run in a READ ONLY transaction with a time and row limit; SQLite files and spreadsheets are opened read-only.
  • Charts picked from the data. Dates become lines, labels become bars, a single row becomes headline numbers, anything else a table. The agent can still choose every chart itself.
  • One call per board. draw fetches and lays out a whole board, with notes, side-by-side rows and titled sections, in a single tool call.
  • Recipes. A board worth repeating becomes a one-call recipe with parameters. Your app ships its own, and the agent saves new ones.
  • Show sources. Every chart, table and number can show the query behind it.
  • Messy spreadsheets welcome. Title rows, "Total" rows, N/A, amounts typed as text and text dates are all handled.
  • Your app, your components. Boards can use your own React components and run your app's actions, and the agent can see what is on screen.
  • Any MCP agent. showboard init --agent writes the settings for Claude Code, Codex, OpenCode, BharatCode, Gemini CLI, Cursor, VS Code, Antigravity and Windsurf.
  • A pane beside the terminal. showboard pane for any agent. In Claude Code, one plugin install brings the server and a pane beside the chat.
  • A cheaper model for new boards. In Claude Code, a board-builder agent on Sonnet builds new kinds of board in its own small context.
  • No extra API key. It runs on the agent you already use.

Works with your agent

Showboard is an MCP server, so any coding agent that speaks MCP can use it. showboard init --agent <names> writes the settings for each one you name (comma separated, or all); with no --agent, it sets up Claude Code plus any agent the folder already has settings for.

Agentinit writesNotes
Claude Code.mcp.jsonApprove the server when Claude Code first asks. Also gets the board-builder agent.
Codex.codex/config.tomlCodex reads it only in a trusted project.
OpenCodeopencode.jsonopencode mcp list shows it connected.
BharatCodeopencode.jsonA fork of OpenCode, so it reads the same entry. Sign in with bharatcode auth login; bharatcode mcp list shows it connected.
Gemini CLI.gemini/settings.jsonTrust the folder when Gemini CLI asks; gemini mcp list shows it connected.
Cursor.cursor/mcp.jsonNames the project folder with --root, since Cursor starts servers elsewhere.
VS Code.vscode/mcp.jsonUses ${workspaceFolder}; start it under MCP Servers, then use agent mode.
Antigravity~/.gemini/config/mcp_config.jsonUser-wide, so the entry names the project folder. Named only on purpose: not part of all.
Windsurf~/.codeium/windsurf/mcp_config.jsonUser-wide, like Antigravity.

Boards have been drawn end to end in Claude Code. For the other agents, the settings init writes have been checked to load and connect, and the server answers their MCP requests; a live session in each is still to come.

Put boards in your own app

npm install showboard zod

The React parts need React 19. Postgres support (pg) comes with the package.

Server. The handler takes a fetch Request and returns a Response, so any Node server can mount it.

import { createShowboard } from "showboard/server";

const showboard = await createShowboard({
  db: process.env.DATABASE_URL,      // a Postgres URL, a SQLite file, or { pool } with your own pg Pool
  boardsDir: ".showboard/boards",    // keep boards across restarts
});
const handle = showboard.handler({ basePath: "/showboard" });

app.all("/showboard/*", (c) => handle(c.req.raw));            // Hono
// node:http and Express: toNodeListener(handle) from "showboard/server"

Browser.

import { Board, BoardList, ShowboardProvider } from "showboard/react";
import "showboard/styles.css";

<ShowboardProvider url="/showboard" onBoard={() => navigate("/board")}>
  <App />
</ShowboardProvider>;

// On the page that holds the agent's answers:
<Board />        {/* the board shown last */}
<BoardList />    {/* saved boards; click one to open it */}

Your agent. In your project folder, then start your app and your agent:

npx showboard init --url http://localhost:3000/showboard --agent claude,codex

Your agent's own login covers your own and internal dashboards; putting Showboard in front of your customers needs a model API key instead.

More examples: a whole board in one call, recipes, your own components, actions and state, rows your server computes

A whole board in one call. What the agent sends to draw. Each part brings its own SQL; the first part becomes a line per channel, the second asks for a pie:

{
  "title": "Orders by channel, {year}",
  "params": { "year": "2026" },
  "items": [
    { "note": "Paid orders only.", "tone": "info" },
    { "row": [
      { "title": "By month",
        "sql": "SELECT substr(ordered_at, 1, 7) AS month, channel, count(*) AS orders FROM orders WHERE status = 'paid' AND substr(ordered_at, 1, 4) = :year GROUP BY 1, 2" },
      { "title": "Share", "show": "pie",
        "sql": "SELECT channel, count(*) AS orders FROM orders WHERE status = 'paid' AND substr(ordered_at, 1, 4) = :year GROUP BY 1" }
    ] }
  ],
  "save_as": { "name": "channel_orders", "about": "Paid orders by channel for one year." }
}

The same board for another year is now one recipe call of a few hundred tokens:

{ "name": "channel_orders", "params": { "year": "2025" } }

Recipes your app ships. :year and :limit become real query parameters, never text pasted into the SQL:

createShowboard({
  db,
  recipes: [{
    name: "top_products",
    about: "A year's best-selling products by paid revenue.",
    title: "Top products of {year}",
    params: { year: { default: "2026" }, limit: { default: 10 } },
    items: [{
      title: "Revenue by product",
      sql: `SELECT p.name AS product, round(sum(i.qty * i.unit_price), 2) AS revenue
            FROM order_items i JOIN orders o ON o.id = i.order_id JOIN products p ON p.id = i.product_id
            WHERE o.status = 'paid' AND substr(o.ordered_at, 1, 4) = :year
            GROUP BY p.name ORDER BY revenue DESC LIMIT :limit`,
      formats: { revenue: "currency" },
    }],
  }],
});

Your own components next to the built-in ones:

import { z } from "zod";
import type { ShowboardComponent } from "showboard/react";

const props = z.object({ sku: z.string().describe("Product SKU, e.g. DSK-AERO") });

export const ProductCard: ShowboardComponent<typeof props> = {
  description: "The shop's product card: name, price and units sold this year.",
  props,
  render: ({ props }) => <ProductTile sku={props.sku} />,   // a component you already have
};

const COMPONENTS = { ProductCard };   // a module constant: a new object redraws every board
<ShowboardProvider url="/showboard" components={COMPONENTS}>…</ShowboardProvider>;

Actions the agent can run, and state it can see:

import { useShowboardAction, useShowboardState } from "showboard/react";

const filterOrdersInput = z.object({ month: z.string().describe("YYYY-MM") });   // outside the component

function ClaudeHooks({ page, setPage, setFilters }) {
  useShowboardState("page", page);   // the agent reads it with get_screen
  useShowboardAction({
    name: "filter_orders",
    description: "Open the Orders page for one month.",
    input: filterOrdersInput,
    run: ({ month }) => {
      setFilters({ month });
      setPage("orders");
    },
  });
  return null;
}

The agent runs an action with ui_act, and a board can carry an ActionButton that runs one.

Rows your server computes, offered to the agent by name:

createShowboard({
  db,
  sources: [{
    name: "stock_levels",
    description: "Units in stock per product, from the warehouse system.",
    input: z.object({ category: z.string().optional() }),
    run: ({ category }) => warehouse.stockLevels(category),   // an array of plain objects
  }],
});

Tools your agent gets

ToolWhat it does
describe_dataLists the tables and columns, the app's sources and the recipes
recipeDraws a ready-made board for new values, in one call
drawFetches and draws a whole board in one call
query_dataRuns one read-only SELECT and keeps the rows as a named dataset (with a database)
use_sourceGets rows your server computes (when your app has sources)
show_boardThe long form: a json-render layout the agent writes element by element; also reopens a saved board
list_boardsLists the saved boards
get_screenWhat the browser shows: the page's state, its actions and its components
ui_actRuns one of the page's actions

Showboard tells the agent to reach for a recipe first, then draw. New recipes reach the agent without a restart where it listens for tool-list changes, as Claude Code does; describe_data lists them for the rest.

API

ExportKindPurpose
createShowboardfnOpens your database or files; returns the tools and the HTTP handler.
toNodeListener, servefnMount the handler on node:http or Express, or serve it on its own.
ShowboardProvider (/react)componentConnects the page to the handler and holds the board on screen.
Board, BoardList (/react)componentThe board shown last, and the saved boards.
useShowboardAction, useShowboardState (/react)hookActions the agent can run, and state it can see.
formatValue (/react)fnPrints numbers the way boards do, for your own components.
boardToText (/text)fnA board as lines of styled text, for a pane of your own.
showboard serve | mcp | init | paneCLIShowboard's own board page, the MCP server, setup for each agent, and the terminal pane.
showboard guide | doctorCLISetup steps written for coding agents, and a check of the setup as each agent will meet it.

The full reference, with every option, prop, tool, flag and the chart-picking rules, is in docs/reference.md.

Safety

Your agent can read your data. It cannot change it, and in your app it can do only what you let it.

  • Postgres: each query runs in a READ ONLY transaction as a single statement, with a time limit (5 s) and a row limit (5,000).
  • SQLite: the file is opened read-only, with the same row limit.
  • Spreadsheets: loaded into an in-memory copy that refuses writes. Your files are only read.
  • SQL: only SELECT (and WITH … SELECT, VALUES, TABLE) is accepted.
  • Actions: the agent can run only the actions your app registers with useShowboardAction, each with an input your schema checks; it cannot click or type anywhere else.
  • HTTP: the handler answers only localhost and 127.0.0.1, and refuses requests from other sites' pages, so a website open in your browser cannot run the tools.

Use a read-only database role anyway.

Limits

  • Notes are the agent's own words. Charts, tables and headline numbers read their values from query results. A note is text the agent writes: it is told to quote only figures it has read, but its conclusions can still be wrong. In testing, Claude once named the wrong product as the units leader, because it had only queried the top 10 by revenue. Tick Show sources to check.
  • The pane draws charts as text. Its braille lines and block bars carry the same figures, at a terminal's resolution; the board page has the full charts.
  • A board is a snapshot. It keeps the rows it was drawn from, so opening it next week shows the numbers as they were then. Ask again, or run its recipe, for fresh ones.
  • Big results are cut. A query keeps at most 5,000 rows, and a chart draws at most 6 lines, or 4 bars per label. The agent is told what was left out, so it can aggregate or filter in SQL.

FAQ

Does my data leave my computer?

Showboard itself runs on your computer, answers only localhost, and sends nothing anywhere. The rows a query returns go to your agent, and so to the agent's model, like anything else your agent reads.

Do I need an API key?

No. Showboard runs on the coding agent you already use, with the login it already has. Putting Showboard in front of your customers is different: that needs a model API key.

Can the agent change my data, or click around my app?

No. Every query is read-only, and in your app the agent can run only the actions you register, with inputs your schema checks. See Safety.

Does it work with agents other than Claude Code?

Yes, with any agent that speaks MCP. showboard init --agent writes the settings for Codex, OpenCode, BharatCode, Gemini CLI, Cursor, VS Code, Antigravity and Windsurf. Claude Code is the one tested end to end so far; see Works with your agent.

Roadmap

  • A pane beside the terminal: showboard pane for any agent, and a Claude Code mod
  • Settings for Codex, OpenCode, BharatCode, Gemini CLI, Cursor, VS Code, Antigravity and Windsurf
  • Publish to npm
  • A leaner launch that trims Claude Code's fixed prompt, the biggest share of what a board costs
  • A board-builder agent for the agents besides Claude Code that have subagents

Contributing

Contributions are welcome, AI-assisted ones included. Read your diff before you send it, and make sure the tests pass. For anything bigger than a fix, open an issue first. CONTRIBUTING.md has the details.

npm install
npm run build        # the package, its board page and the Claude Code mod's renderer
npm test             # SHOWBOARD_TEST_PG=<postgres url> also runs the Postgres tests
npm run test:pane    # the Claude Code mod, in Claude Code's own plugin test kit
npm run typecheck
npm run demo
FolderWhat is in it
packages/showboard/src/servercreateShowboard, the tools, read-only database access, spreadsheet loading, the HTTP handler
packages/showboard/src/reactShowboardProvider, Board, the built-in components and the hooks
packages/showboard/src/specThe component catalog, number formats and board checks
packages/showboard/src/textBoards drawn as text, for the panes
packages/showboard/src/cliThe serve, mcp, init and pane commands, and each agent's settings
packages/showboard/src/viewerShowboard's own board page
plugins/claude-codeThe Claude Code plugin: a Showboard server and the pane beside the chat, listed for /plugin install in .claude-plugin/marketplace.json
plugins/claude-desktopThe Claude desktop extension: manifest.json and build.mjs, which writes showboard-<version>.mcpb
examples/The demo shop and the sample spreadsheets
bench/The cost benchmark

License

MIT. See LICENSE.

Star history

Star history of rohanbeingsocial/showboard

If Showboard saved you some tokens, a ⭐ helps other people find it.