DEV Community

bmarkov
bmarkov

Posted on

The Svelte Data Grid That Ships Its Own MCP Server

Svelte Data Grid MCP

Ask a coding model to wire up a Svelte 5 data grid and you usually get code that looks right and does not run. The prop names drift in from a React grid, the reactivity is Svelte 4 stores, and the version it learned from shipped a year and a half ago. You paste the error back, it apologises, it invents a slightly different API.

That failure mode is the thing SvGrid is built around. It is a Svelte 5 native data grid: a headless core plus a <SvGrid> renderer, virtualization, grouping, editing, server-side data, keyboard and screen-reader support. The core package @svgrid/grid is MIT.

The part worth writing about is what sits on top of that. AI shows up twice in this product: once at build time, so your editor writes correct grid code, and once at runtime, so your users can talk to their data. Here are the five pieces that matter.

1. An MCP server, so the model reads the API instead of remembering it

Model Context Protocol is the open standard for exposing tools to LLM clients. SvGrid ships one: @svgrid/mcp, MIT licensed, listed in the official MCP registry as com.svgrid/svgrid.

One command in Claude Code:

claude mcp add svgrid -- npx -y @svgrid/mcp
Enter fullscreen mode Exit fullscreen mode

Or the same server in Cursor, Zed, Claude Desktop, or anything else that speaks MCP over stdio:

{
  "mcpServers": {
    "svgrid": { "command": "npx", "args": ["-y", "@svgrid/mcp"] }
  }
}
Enter fullscreen mode Exit fullscreen mode

Eight of the tools cover docs and examples:

Tool What it returns
list_examples Every demo: id, title, one-line blurb
get_example_source The full .svelte source of one demo, verbatim
list_docs / get_doc Doc slugs, then the markdown of a page
search_docs Substring search across the docs with excerpts
get_api_reference The curated public API surface, grouped by category
introspect_source A draft entity schema from a Drizzle file or sample rows
scaffold_entity Runnable SvelteKit files for one entity

Two details do most of the work here. First, the corpus is inlined into the package at build time, so answers are pinned to the version you installed rather than to whatever the model absorbed during training. Second, get_example_source returns real working files, all 360+ of them, so "build me a grid that groups by department and shows a sparkline per row" starts from code that already compiles.

It runs locally over stdio. No API key, no telemetry, no outbound call. stdout is JSON-RPC, logs go to stderr.

If you do not want to run a server, the same grounding ships as static files you can paste into a custom GPT, a Claude project, or your own agent's system prompt:

const topicMap = await fetch('https://svgrid.com/llms.txt').then((r) => r.text())
const schemas  = await fetch('https://svgrid.com/schemas/index.json').then((r) => r.json())
Enter fullscreen mode Exit fullscreen mode

llms.txt is the ~10 kB topic map, llms-full.txt is every doc page concatenated, and schemas/index.json gives you JSON Schema for ColumnDef and the <SvGrid> props so a generated config can be machine-validated before you ever run it.

2. Natural-language filtering that cannot invent a column

Now the runtime side. The AI helpers live in @svgrid/grid itself, MIT, no license key and no separate package.

import { aiFilter } from '@svgrid/grid'

const plan = await aiFilter(api, 'accounts losing momentum in EMEA, by NPS')
// {
//   filters: [
//     { field: 'region', operator: 'equals',   value: 'EMEA' },
//     { field: 'nps',    operator: 'lessThan', value: '30' },
//   ],
//   sort: [{ field: 'nps', desc: false }],
//   rationale: 'EMEA region, low NPS, sorted ascending.',
// }
Enter fullscreen mode Exit fullscreen mode

Three things keep this from becoming a party trick:

  • The prompt is grounded in your columns. Before the call, the grid embeds the live column schema (names, types, sampled values) so the model picks real field names.
  • A hallucination guard on the way back. If the model still returns a column that does not exist, that clause is dropped rather than handed to setFilter, which would throw. You would rather lose a clause than crash the page.
  • It returns a plan and does not apply it. That gives you the "here is what I would do, accept?" preview for free. Pass { apply: true } when you want it committed directly.

For an analyst-facing table this replaces a dozen per-column filter operators with one text box.

3. Smart fill, and paste from wherever the data actually came from

Smart fill is the spreadsheet feature. The user types one or two worked examples in a column, and the model proposes the rest:

const result = await aiSmartFill(api, {
  field: 'tier',
  examples: [
    { input: { company: 'Northwind' }, output: 'enterprise' },
    { input: { company: 'Helios' },    output: 'growth' },
  ],
})
// result.predictions: [{ rowIndex, value, confidence }, ...]
Enter fullscreen mode Exit fullscreen mode

You decide what happens next: accept all, accept per cell, or write the prediction to a shadow field and render a confidence pill in the cell.

Smart paste is the one that RevOps users react to. Drop in CSV, TSV, JSON, a vCard, a Markdown table copied out of Slack, an email signature block, or a paragraph of prose, and the parser detects the format and maps it to typed rows. Every parsed row then goes through three normalization passes before the preview renders: email typo correction (gmial.com), phone rewriting to a consistent +CC AAA BBB CCCC shape, and name cleaning that strips Dr. / Jr. and rewrites "Last, First". Duplicate emails collapse into one row with missing fields merged in.

4. One adapter, no bundled model

Every AI call in the grid routes through a single async function you register once at boot:

import { setAIProvider, type AIProvider } from '@svgrid/grid'

const provider: AIProvider = async ({ prompt, responseFormat, signal, task }) => {
  const r = await fetch('/api/ai', {
    method: 'POST',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify({ prompt, responseFormat, task }),
    signal,
  })
  if (!r.ok) throw new Error(`AI provider returned ${r.status}`)
  return r.text()
}

setAIProvider(provider)
Enter fullscreen mode Exit fullscreen mode

The grid ships no model client at all. Model choice, routing, key handling, and what leaves the browser stay yours. signal is forwarded so you can cancel in flight, and task is tagged ('filter' | 'smart-fill' | 'summarize' | 'classify') so you can route cheap tasks to a small model and summaries to a stronger one.

That one provider powers the whole set:

aiFilter(api, query, opts?)        // NL query -> filter + sort plan
aiSmartFill(api, opts)             // examples -> proposed column values
aiSummarize(api, opts)             // row / selection / group / all -> text + bullets
aiClassify(api, opts)              // free-text cells -> bucketed labels
aiExport(api, query, opts?)        // NL query -> filter + group + format, then export
aiFindAnomalies(api, opts?)        // scan a slice for outliers and bad values
enableAiCharting(api)              // adds an AI button to the chart panel
Enter fullscreen mode Exit fullscreen mode

With enableAiCharting, "revenue by country, stacked by product" becomes a chart config (type, group-by, split-by, measure, aggregate) applied live.

Helpers request responseFormat: 'json' and the grid parses the reply, stripping a single markdown fence first so models that wrap output in a code block still parse. Malformed output gives you a typed error rather than a silent wrong answer.

Nothing is imported until you import it, so if you do not want natural language anywhere, these tree-shake away and cost nothing. A bundled mockAIProvider returns deterministic canned shapes per task, which is how every AI demo on the site runs with no key.

5. The grid is a tool surface

The imperative SvGridApi maps cleanly onto function calling, so an agent can drive the UI rather than just describe it. Each method becomes one tool:

const tools = [
  { type: 'function', function: { name: 'setFilter',  /* columnId, operator, value */ } },
  { type: 'function', function: { name: 'setSort',    /* columnId, direction */ } },
  { type: 'function', function: { name: 'setGroupBy', /* columnIds */ } },
  { type: 'function', function: { name: 'clearAllFilters', parameters: { type: 'object' } } },
]
Enter fullscreen mode Exit fullscreen mode

Point getDisplayedRows() at a read-only summariser and the model sees exactly what the user sees, filters and sorting and grouping already applied, instead of the raw dataset.

The same idea runs one level up. Alongside the docs tools, the MCP server exposes 27 studio_* tools that drive the same validated project model the visual designer uses: add entities, screens, blocks and components, bind a data source, set auth, RBAC, theme, the typed data layer, and the deploy target, then emit a full runnable SvelteKit app. Every edit goes through the model's own functions and validateProject, so an agent that guesses wrong gets a validation error instead of a broken app. Those generators are part of the commercial Studio tier; the docs and example tools are free.

Worth a look if

You are building tables in Svelte 5 and you are tired of correcting your assistant's grid code, or you want natural-language filtering in an app without shipping a model client and a vendor lock-in with it.

npm create @svgrid@latest
claude mcp add svgrid -- npx -y @svgrid/mcp
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
topstar_ai profile image
Luis Cruz

The integration of the Model Context Protocol (MCP) with SvGrid is a clever approach to ensure that the AI models interact with up-to-date APIs, which can significantly reduce errors stemming from version mismatches. By inlining the corpus at build time, you not only maintain consistency but also enhance the development experience for users. I'm especially intrigued by the potential of the natural-language filtering capability; it seems like a powerful way to bridge the gap between user intent and data querying. If you're considering expanding the features or improving the AI interactions, I’d love to explore a paid collaboration to help enhance this aspect further! What other functionalities are you envisioning for the AI helpers in the future?

Collapse
 
bmarkov profile image
bmarkov

We will extend it in this direction: AI building a full SvelteKit app with Svelte Data Grid - SvGrid and the other Svelte UI Components part of it. See: https://svgrid.com/studio/