Skip to main content
Glama

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

Quick start  ·  How it works  ·  Benchmark  ·  Docs

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 own

Claude Code + Showboard

You get

Paragraphs, or an HTML file it wrote

A board of charts, tables, headline numbers and notes

You see it

In the terminal, or in a file you open

In your browser, inside your app, or beside your terminal

The numbers come from

Python it wrote and ran

Read-only SQL, one click away under every chart

24 answers, measured

$4.77 and 24.3 minutes

$1.78 and 7.5 minutes

Related MCP server: mcp-server-motherduck

Benchmark

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

  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.

Excel and CSV, no app needed

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

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

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

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.

Agent

init writes

Notes

Claude Code

.mcp.json

Approve the server when Claude Code first asks. Also gets the board-builder agent.

Codex

.codex/config.toml

Codex reads it only in a trusted project.

OpenCode

opencode.json

opencode mcp list shows it connected.

BharatCode

opencode.json

A 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.json

Trust the folder when Gemini CLI asks; gemini mcp list shows it connected.

Cursor

.cursor/mcp.json

Names the project folder with --root, since Cursor starts servers elsewhere.

VS Code

.vscode/mcp.json

Uses ${workspaceFolder}; start it under MCP Servers, then use agent mode.

Antigravity

~/.gemini/config/mcp_config.json

User-wide, so the entry names the project folder. Named only on purpose: not part of all.

Windsurf

~/.codeium/windsurf/mcp_config.json

User-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.

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

Tool

What it does

describe_data

Lists the tables and columns, the app's sources and the recipes

recipe

Draws a ready-made board for new values, in one call

draw

Fetches and draws a whole board in one call

query_data

Runs one read-only SELECT and keeps the rows as a named dataset (with a database)

use_source

Gets rows your server computes (when your app has sources)

show_board

The long form: a json-render layout the agent writes element by element; also reopens a saved board

list_boards

Lists the saved boards

get_screen

What the browser shows: the page's state, its actions and its components

ui_act

Runs 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

Export

Kind

Purpose

createShowboard

fn

Opens your database or files; returns the tools and the HTTP handler.

toNodeListener, serve

fn

Mount the handler on node:http or Express, or serve it on its own.

ShowboardProvider (/react)

component

Connects the page to the handler and holds the board on screen.

Board, BoardList (/react)

component

The board shown last, and the saved boards.

useShowboardAction, useShowboardState (/react)

hook

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

formatValue (/react)

fn

Prints numbers the way boards do, for your own components.

boardToText (/text)

fn

A board as lines of styled text, for a pane of your own.

showboard serve | mcp | init | pane

CLI

Showboard's own board page, the MCP server, setup for each agent, and the terminal pane.

showboard guide | doctor

CLI

Setup 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

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.

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.

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.

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

Folder

What is in it

packages/showboard/src/server

createShowboard, the tools, read-only database access, spreadsheet loading, the HTTP handler

packages/showboard/src/react

ShowboardProvider, Board, the built-in components and the hooks

packages/showboard/src/spec

The component catalog, number formats and board checks

packages/showboard/src/text

Boards drawn as text, for the panes

packages/showboard/src/cli

The serve, mcp, init and pane commands, and each agent's settings

packages/showboard/src/viewer

Showboard's own board page

plugins/claude-code

The Claude Code plugin: a Showboard server and the pane beside the chat, listed for /plugin install in .claude-plugin/marketplace.json

plugins/claude-desktop

The 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

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

Available Tools

8 tools
describe_dataA

List what you can read: the database tables and columns query_data can use (with estimated row counts), and the app's named data sources for use_source. Call it before writing SQL against tables you have not seen.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does disclose the payload: tables, columns, estimated row counts, and named data sources, including the "estimated" qualifier that warns against relying on counts as exact. It stops short of saying whether the listing is live/cached or how large a result can be, which matters for a zero-parameter exhaustive listing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, no filler, and the content of the listing is front-loaded before the usage instruction. Every clause earns its place by naming either a return field or a consumer tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, yet the description enumerates the return contents well enough for an agent to know what it will get and to route it to query_data or use_source. Minor gap: no hint about result size, freshness, or what an empty catalog means.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes no parameters, so there is nothing to disambiguate and the baseline of 4 applies. The description correctly implies a single no-argument call returning the full catalog.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a concrete verb and the exact resources enumerated: database tables/columns usable by query_data, plus the app's named data sources for use_source. It distinguishes itself from the two sibling tools that consume its output, so an agent can tell what it returns versus what query_data and use_source do.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Call it before writing SQL against tables you have not seen" is an explicit when-to-use rule with a clear precondition (unfamiliar tables). Naming query_data and use_source as the downstream consumers makes the alternative-selection implicit but unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

drawA

Draw a board on the user's screen in one call. items, in reading order:

  • a part: sql (one read-only SELECT), dataset or source, with an optional title. The chart is picked from its rows: dates with numbers → line, labels with numbers → bars, one row → headline numbers, else a table; rows like (date, name, value) get a line per name. Choose yourself with show, x, y, series and formats, or draw it with any component and props (its dataset is filled in).

  • {note, title?, tone?}: your text. Quote only figures you have read.

  • {row: [parts]} side by side; {section, subtitle?, items} a titled group. The database computes every number: aggregate, rebase and round in SQL. Put values the user may change in params (:name in the SQL) and add save_as to keep the board as a recipe, so the same board for other values is one recipe call. Returns the rows of each part (the first and last of long ones) to check. Components: Grid {columns?}: Places its children side by side in equal columns, wrapping to new rows. Section {title, subtitle?}: A titled group of children, stacked. Metric {label, dataset, field, row?, format?, caption?}: One headline number read from a dataset cell (row 0 unless row is set). LineChart {dataset, x, y, title?, format?}: Lines over x (dates or ordered labels), one line per y column. BarChart {dataset, x, y, title?, format?, horizontal?}: Bars per x category, one bar per y column. horizontal suits long labels. PieChart {dataset, label, value, title?, format?}: Donut of value by label; beyond 7 slices the rest are grouped as Other. Table {dataset, columns?, limit?, title?}: Rows of a dataset. columns picks and orders them (all when omitted): column names, or { field, label?, format? }. Note {text, title?, tone?}: Your explanation in plain text. Lines starting with '- ' become bullets; bold works. tone colours it. ActionButton {label, action, input?}: A button that runs one of the app's actions (see get_screen) with the given input. The app can add its own components; get_screen lists them.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNoReplace this board instead of adding one
itemsYes
titleYesMay use {param} to show a value
paramsNoValues for :name placeholders in the SQL; lists as arrays
save_asNoKeep as a recipe; params become its inputs
preview_rowsNoRows of each part returned to you (default: all of a small result, else the first 3 and the last)

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and mostly delivers: it constrains SQL to a single read-only SELECT, states that every number is computed by the database, discloses the return behavior ('returns the rows of each part, the first and last of long ones'), and explains that save_as persists a reusable recipe. It does not address side effects like what happens to existing boards or any permission/rate constraints.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action, then a bulleted item grammar and a component glossary, which is the right structure for a deeply nested schema. It is longer than ideal and the component glossary largely restates what the schema already documents (e.g. Note text/bullets/bold, tone), which is redundant weight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter tool with deep nesting and no output schema, the description covers the essentials: item shapes, chart auto-selection rules, SQL/params discipline, recipe reuse, return-value behavior, and an escape hatch via get_screen for custom components. Nothing an agent needs to construct a valid call is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 83%, so the baseline is 3; the description earns an extra point by explaining how params (:name placeholders) tie to SQL, how save_as turns params into recipe inputs, and how show/x/y/series/formats interact to pick a chart versus providing component+props. It adds genuine semantics beyond the field-level text, though it doesn't clarify id or preview_rows.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a precise verb+resource+scope: 'Draw a board on the user's screen in one call.' It then enumerates the item grammar concretely (part / note / row / section), so an agent knows exactly what the tool produces versus a read-only sibling like query_data or describe_data. It also points at get_screen for app-specific extensions, which sharpens its boundary.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives actionable routing guidance: use recipe when the same board must be re-rendered for other param values, use get_screen to discover app actions/components, and 'aggregate, rebase and round in SQL' rather than post-processing. What's missing is an explicit statement of when to call draw versus show_board/list_boards, so the create-vs-view boundary is left implicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_screenA

What the user's browser shows now: the page and app state the app publishes, the actions you can run with ui_act (with their inputs), any components the app adds for boards, and the board on screen. Call it before ui_act, and to see what the user is looking at.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description discloses the substantive behavior: it is a snapshot read of live screen state and a required precursor to ui_act. It does not explicitly state that the call is side-effect free, nor how fresh the snapshot is or what happens if no browser is attached, keeping it below a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core identity before the usage rule. The first sentence is a dense four-item enumeration packed into one clause chain, but every item carries information an agent needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description compensates by enumerating what the snapshot contains, which is exactly what is needed. Missing only the relationship to sibling board tools (show_board, list_boards) for an agent deciding where to look first.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so the baseline is 4 and there is nothing for the description to disambiguate. The parenthetical about ui_act inputs describes return content, not this tool's inputs.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific resource — the current browser screen — and enumerates its contents (page/app state, ui_act actions with inputs, board components, active board). An agent can distinguish it from ui_act and show_board, though the boundary with show_board/describe_data is only implied, not spelled out.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

"Call it before ui_act, and to see what the user is looking at" gives a concrete precondition and a concrete use case. It stops short of naming when NOT to use it (e.g. vs show_board or describe_data), so it is clear context rather than full routing guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_boardsA

List saved boards, newest first. show_board with an id reopens one.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo

TDQS

A3.6/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the full behavioral burden. It discloses sort order ('newest first'), which is genuinely useful, but says nothing about the default limit, whether results are paginated or capped, or what a board record contains—all behavior an agent must know before calling a list tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences, zero filler, with the core purpose and ordering front-loaded and the sibling routing placed second. Every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With one optional parameter, no output schema, and no annotations, the surface area is small, so the terse description is close to adequate. Still, an agent cannot tell what the default page size is or how much data comes back, which matters for a listing call whose main risk is unbounded results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%: the single 'limit' parameter has only min/max bounds and no prose. The description never mentions limit at all—not its default value, not whether omitting it returns all boards or a capped page. The one parameter present is therefore undocumented in both places.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('List saved boards') plus the ordering ('newest first'), and explicitly distinguishes itself from the sibling show_board, which retrieves a single board by id. An agent can pick between the two without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The second sentence names the alternative (show_board with an id) and the condition that selects it, so the list-vs-retrieve fork is covered. It stops short of stating when not to use this (e.g., when an id is already known, skip listing), so it is clear context rather than a full when/when-not rule set.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

query_dataA

Run one read-only SQL SELECT against the app's SQLite database and keep the rows as a dataset named name that boards can draw. The database computes every number: aggregate, sort and round in SQL, not in your head. Returns the columns, the row count and the first rows. At most 5000 rows per query. Reusing a name replaces that dataset.

ParametersJSON Schema
NameRequiredDescriptionDefault
sqlYes
nameYesDataset name boards will use, e.g. top_products
preview_rowsNoRows to return to you (default 15)

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the behavioral burden well: read-only single SELECT, 5000-row cap, return shape (columns, row count, first rows), and that reusing a name replaces the existing dataset. It omits error behavior, timeouts, and permission requirements, but the core operational traits are disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Four tight sentences, front-loaded with the action and resource, then the compute guidance, return shape, limits, and replacement semantics. Nothing redundant or padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with no output schema and no annotations, the description covers return shape, row limits, and dataset-replacement behavior. Error handling and permission/scope expectations are the main missing pieces, but an agent has enough to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 67%, and the description adds real meaning beyond the schema for the two most important parameters: `name` becomes the dataset boards draw and its reuse replaces the old dataset; `sql` must be one read-only SELECT. preview_rows semantics are left to its schema description, which is adequate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Run one read-only SQL SELECT against the app's SQLite database') plus the side effect ('keep the rows as a dataset named `name` that boards can draw'). The dataset-materialization purpose clearly separates it from schema-inspection siblings like describe_data, even without naming them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied: it is the tool for computing numbers in SQL rather than 'in your head', and read-only SELECT signals its scope. However, it never names describe_data as the alternative for discovering schema, nor states when not to use it, so routing guidance is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

recipeA

Draw a ready-made board in one call: name a recipe and its values (lists as arrays). Use one whenever it fits the question; draw makes new kinds of boards. note puts your text at the top (quote only figures you have read); title replaces the recipe's. No recipes yet: draw with save_as adds one.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNoReplace this board instead of adding one
nameYes
noteNo
titleNo
paramsNo

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations exist, so the description carries the full burden. It does disclose real behavior: 'id' replaces an existing board instead of adding one, 'note' places text at the top, 'title' replaces the recipe's title. However it says nothing about what happens with an unknown recipe name, whether the board is persisted/shown, or what the call returns.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Tight, front-loaded opening sentence followed by routing and per-parameter notes; nearly every clause carries information. It is dense to the point of being cryptic in places ('quote only figures you have read'), but no sentence is wasted.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and no annotations, and the tool creates/replaces persisted boards with a nested params object. The description covers the parameter semantics but omits error behavior for unknown recipe names and any indication of the result of a successful call, leaving a meaningful gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 20% (only 'id' is described inline), but the description compensates well: it explains name (the recipe), params ('its values, lists as arrays'), note (text at the top, only quote figures you have read), and title (replaces the recipe's). Only the nested param value constraints and the replace semantics interplay are left thin.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: 'Draw a ready-made board in one call' from a named recipe, and contrasts it with the sibling 'draw', which 'makes new kinds of boards'. An agent can differentiate the two without opening schemas, though what a 'recipe' actually is remains implicit (a saved board template).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit routing: 'Use one whenever it fits the question; draw makes new kinds of boards' names the alternative and the condition that selects it. It also covers the empty-state case ('No recipes yet: draw with save_as adds one'), though it never says when *not* to use a recipe beyond preferring draw for new board kinds.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

show_boardA

The long form of draw: a json-render spec you wire yourself, for what draw cannot say. Pass only id to reopen a saved board. { "root": "", "elements": { "": { "type": "", "props": {…}, "children": ["", …] } } }, with the components listed under draw. Every number comes from a dataset (query_data or use_source): components take a dataset name and column names, and any other prop can read a cell with { "$state": "/data///" }. Do not type figures into props. In a Note, only quote figures you read from a dataset. Pass id (from an earlier board) to change that board in place.

ParametersJSON Schema
NameRequiredDescriptionDefault
idNo
specNo
titleNo

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description must carry the behavior burden, and it does disclose the important parts: passing `id` mutates an existing board in place, and figures must be data-bound rather than typed into props. It does not say whether the supplied spec replaces or merges with an existing board, what is returned, or whether the write is reversible.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The framing sentence is front-loaded and each subsequent sentence covers a distinct concern (spec shape, data binding rule, id semantics). The inline JSON fragment is dense but functional; nothing reads as padding, though the middle paragraph is heavier than it needs to be.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with an untyped free-form spec parameter, no annotations and no output schema, the description covers the essentials of constructing a spec and binding data. It still leaves the agent guessing about create-vs-render semantics, spec/id precedence, and the unused `title` parameter, so it is adequate rather than complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and `spec` is declared as a bare `{}` with no structure, so the description's root/elements/props/children breakdown and the `$state` binding syntax add real value. However, `title` is never mentioned at all, and the component vocabulary is outsourced to `draw`'s documentation rather than restated, so the compensation is partial.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description frames the tool concretely as the long-form counterpart of `draw` and states it consumes a self-authored json-render spec, with `id` alone reopening a saved board. It distinguishes itself from the sibling `draw` by capability ('for what draw cannot say'), though it never plainly says the board is rendered to the user, leaving that inference to the agent.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It tells the agent when to reach for this instead of `draw` (when the hand-built spec is needed) and what the two `id` modes mean — reopen a saved board vs. change it in place. What's missing is any when-not guidance, e.g. what happens if both `spec` and `id` are supplied, or when to prefer `list_boards`/`get_screen` instead.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

ui_actB

Run one of the app's actions in the user's browser: open a page, set a filter, select something. get_screen lists the actions and their inputs. Returns what the action returned.

ParametersJSON Schema
NameRequiredDescriptionDefault
inputNo
actionYes

TDQS

B3.2/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It discloses that execution happens in the user's live browser and that the action's return value is passed through, but says nothing about side effects, reversibility, permissions, error behavior, or whether actions are destructive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences with the core purpose front-loaded and no filler. The final sentence ('Returns what the action returned') is mildly tautological but still communicates passthrough behavior.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a generic dispatcher with a free-form input object, no annotations, and no output schema, the description covers discovery and return passthrough. It is missing safety, failure-mode, and validation context that an agent would need to invoke arbitrary actions confidently.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the schema documents neither the action string's valid values nor the shape of the arbitrary input object. The description compensates partially by saying get_screen lists actions and their inputs, establishing the action/input relationship, but it leaves the input structure entirely external and does not mention the 80-character action limit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: run one of the app's actions in the user's browser, with concrete examples (open a page, set a filter, select something). It distinguishes itself from get_screen by framing that sibling as the discovery mechanism, though 'one of the app's actions' remains somewhat abstract without knowing the app.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Points the agent to get_screen for the list of actions and their inputs, which implies a prerequisite workflow. However, it never explicitly says to call get_screen first, gives no when-not conditions, and does not contrast with siblings like show_board or describe_data.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 8 tool updatesv0.4.0
    • First observeddescribe_data
    • First observeddraw
    • First observedget_screen
    • First observedlist_boards
    • First observedquery_data
    • First observedrecipe
    • First observedshow_board
    • First observedui_act

TDQS

A3.7/5.0

Scored across 8 tools

Disambiguation4/5

Most tools map to a distinct action (introspect, query, list, inspect, act), but three tools — recipe, draw, show_board — all produce boards and their boundaries rest on soft guidance like 'the long form of draw' and 'use a recipe whenever it fits.' The descriptions mitigate the overlap well, but an agent still has to judge which board-authoring path applies.

Naming Consistency3/5

The majority follow a verb_noun or verb-object pattern (describe_data, list_boards, query_data, show_board, get_screen, ui_act, though ui_act inverts to noun_verb). The bare names 'recipe' (a noun) and 'draw' (a bare verb) break the pattern and make the set feel mixed.

Tool Count5/5

Eight tools is well within the sweet spot, and each one earns its place: data introspection, query, three tiers of board rendering, board listing, screen inspection, and browser action. Nothing feels redundant at the count level.

Completeness4/5

The core lifecycle is covered: describe data, query it, render a board (simple or full spec), save/list boards, and inspect/drive the app. Gaps are minor: there is no delete or rename for boards, no way to enumerate saved recipes or manage stored datasets, which agents can work around by reusing names.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive

Related MCP Connectors

Related MCP Servers