Skip to main content
Glama
Mikebenisberchmans

Superbrain Schema-Context MCP

README.md
# Superbrain Schema-Context MCP — POC

A proof of concept for one feature: an **MCP server that gives Superbrain's coding
agent live, on-demand access to a connected database's schema**, instead of dumping
the whole schema into context up front. The UI is a thin shell around it, styled to
match Superbrain's real interface, so the feature can be evaluated in something
close to its real home.

## What this is (and isn't)

- **Real and working:** the MCP server (`/api/mcp`), its 5 schema-retrieval tools,
  the Postgres introspection behind them, and the live agent demo that shows what
  the coding agent actually fetches while it builds.
- **Placeholder:** the rest of the IDE chrome (menus, other panels) and every data
  source except Postgres in the "Connect a data source" modal. These exist to show
  where this feature would live inside the real product, not to be functional.
- The in-app guided tour says this explicitly on first load, so an evaluator isn't
  guessing which parts to take seriously.

## Why this feature

Superbrain's own pitch is a context engine that compresses and prioritizes code
intelligence to cut token usage 60-80% while keeping full repo awareness. Database
schema is the same problem one layer down: an agent building a data app needs
table/column/relationship context to write correct code, and the naive approach —
handing it the full schema as one blob — is exactly the kind of undifferentiated
context bloat Superbrain's architecture is designed to avoid for code. This POC
applies the same idea to schema: **retrieve progressively, scoped to what the
current step actually needs, instead of dumping everything up front.**

## Architecture

```
┌─────────────────┐     MCP (Streamable HTTP)     ┌──────────────────────┐
│  Groq              │ ─────────────────────────────▶│  /api/mcp             │
│  (Responses API,    │◀─────────────────────────────│  (mcp-handler)        │
│  remote MCP tool)    │        tool calls/results     │  5 schema tools       │
└─────────────────┘                                └──────────┬───────────┘
        ▲                                                      │
        │ prompt + trace                                       │ SQL (pg)
        │                                                       ▼
┌─────────────────┐                                ┌──────────────────────┐
│  Next.js UI       │──POST /api/agent─────────────▶│  Demo Postgres         │
│  (IDE-shell)      │                                │  (e-commerce schema)  │
└─────────────────┘                                └──────────────────────┘
```

The agent side runs on **Groq's Responses API** (`openai/gpt-oss-120b`), using Groq's
native **remote MCP** support: you hand Groq an MCP server URL and it handles tool
discovery, calling, and feeding results back to the model server-side, in one API
call — no client-side orchestration loop to write. This is functionally the same
shape as Anthropic's MCP connector or OpenAI's remote MCP API; Groq's implementation
is explicitly built to be a drop-in swap for either. Which model/provider sits behind
`/api/agent` is intentionally decoupled from the MCP server itself — `/api/mcp` never
changes when the LLM provider changes, which is the whole point of building this as a
real MCP server instead of a provider-specific tool-calling shim.

**The five MCP tools** (`lib/schema-context.ts`, exposed via `app/api/mcp/route.ts`):

| Tool | Purpose | Cost |
|---|---|---|
| `list_tables` | Table names, approximate row counts, one-line comments. Nothing else. | Cheapest — always the first call. |
| `search_schema` | Keyword-ranked table search ("orders and payments" → relevant tables only). | Cheap — replaces manual scanning of `list_tables` output. |
| `get_table_schema` | Full columns/types/keys, but only for the table names passed in. | Scoped — never returns the whole DB. |
| `get_related_tables` | One-hop FK graph around a table, both directions. | Scoped — the local join graph, not the full ERD. |
| `get_sample_values` | A few real distinct values for one column. | Scoped — for enum/status columns, capped at 10. |

Each tool result carries an estimated token count back to the UI, so the
**Context Panel** can show exactly what the agent fetched, in what order, and at
what cost — and compare that running total against what a naive "dump the whole
schema as DDL" approach would have cost for the same database
(`getFullSchemaDump` / `getNaiveDumpTokenEstimate` in `lib/schema-context.ts`).

### Key design decisions

- **Progressive disclosure over embeddings, for this POC.** `search_schema` uses
  keyword/comment matching, not vector search. The tool *contract* (query in,
  ranked tables out) is what matters and is what a production version would keep;
  swapping the scoring function for embeddings is an internal implementation
  change, not an interface change. Keyword search was enough to demonstrate the
  pattern without adding an embeddings pipeline to a one-day build.
- **Server-side connection string, not client-supplied.** The datasource modal
  *displays* the demo Postgres credentials for transparency, but the actual
  connection is made server-side via `DEMO_DATABASE_URL`. Letting a public demo
  app accept arbitrary client-supplied connection strings is a real security
  problem (SSRF into internal networks, credential harvesting) — not a corner
  worth cutting even in a demo.
- **One live data source, by design, not by omission.** Redshift/Snowflake/Synapse/
  BigQuery appear in the picker because that's what the real product's picker
  would show, but only Postgres is wired up. The tool contract above is
  database-agnostic (it's just table/column/FK/sample-value retrieval); adding a
  second source means writing a new introspection module behind the same five
  tools, not redesigning the feature.
- **MCP over a bespoke API.** Using the actual Model Context Protocol (via
  `mcp-handler` on Vercel, and Groq's native remote-MCP support on the model side)
  instead of a custom tool-calling shim means this server would work unmodified if
  Superbrain's own agent — or any other MCP-speaking agent/provider — connected to
  it. Swapping the LLM provider (this started as Anthropic, now runs on Groq) only
  touched `/api/agent`; `/api/mcp` didn't change at all. That portability is the
  actual point of building it as an MCP server instead of an API route the agent
  calls directly.
- **Groq's Responses API, not Chat Completions.** Groq explicitly recommends the
  Responses API for MCP workflows — tool discovery, reasoning, and tool calls come
  back as distinct, labeled steps in `output[]`, which is what makes the Context
  Panel's trace possible without extra parsing gymnastics.
- **Single non-streaming agent call for the demo.** `/api/agent` waits for the full
  Claude response (including all MCP tool round-trips) before returning, rather
  than streaming. Simpler to build and debug correctly in the time available;
  streaming the tool-call trace live is the first thing I'd add next (see below).
- **API key stays client-side, in memory only.** The evaluator pastes their own
  Groq key into the app; it's sent straight to this app's own `/api/agent` route
  per-request and never written to storage or logs. A demo app shouldn't ship a
  real production key in a public repo.

## Running it

```bash
npm install
cp .env.example .env.local   # fill in DEMO_DATABASE_URL
npm run seed                  # seeds the demo e-commerce schema (12 tables)
npm run dev
```

Open `http://localhost:3000` → "Connect a Data Source" → PostgreSQL → Connect.

**Note on testing the live agent call locally:** Groq's servers need to reach your
MCP server over a public HTTPS URL — `localhost` isn't reachable from their side.
The agent demo (asking it to build something) only works once deployed (or through
a tunnel like `ngrok http 3000` pointed at your local server, with the origin
detection adjusted accordingly). The MCP server itself and the DB introspection can
be fully tested locally via `/api/db/connect` and by calling `/api/mcp` directly
with the MCP protocol — both are covered above and don't need Groq at all.

### Demo database

Any Postgres works. Free options: [Neon](https://neon.tech) or
[Supabase](https://supabase.com). Create a read-only role for the connection
string used in the app:

```sql
create role demo_reader with login password 'your_password';
grant connect on database superbrain_demo to demo_reader;
grant usage on schema public to demo_reader;
grant select on all tables in schema public to demo_reader;
```

### Deploying

1. Push this repo to GitHub.
2. Import it into Vercel.
3. Set `DEMO_DATABASE_URL`, `NEXT_PUBLIC_DEMO_DB_HOST`, `NEXT_PUBLIC_DEMO_DB_NAME`,
   `NEXT_PUBLIC_DEMO_DB_USER` as environment variables in the Vercel project.
4. Deploy. The MCP server is reachable at `https://<your-app>.vercel.app/api/mcp`
   automatically — `/api/agent` derives that URL from the incoming request, so no
   extra config is needed for the two to find each other.

---

## Product Strategy

**A. If you were building this product, what would you change or add next, and why?**

*The thing I'd prioritize next is exactly what the POC is built around: reducing token usage inside
the iterative build loop by giving the agent proper, task-specific context about the data it's
working with not just code context, but data-platform context before it starts generating.
Right now, if an agent has to write code against a database without that context, it burns
tokens and time discovering the schema through trial and error via failed syntax and logic
checks. Baking a lightweight, on-demand schema/data-context retrieval layer into the core
Architecture engine the same way Token Fold handles code context would extend the
token-reduction story to data-heavy tasks specifically, and should also lift correctness, since
the agent isn't guessing at what it can't see.*

- Streaming the agent's tool-call trace live into the Context Panel instead of
  waiting for the full response, so the "what is it fetching right now" moment
  reads as *live*, not retrospective — closer to how Superbrain's own product
  presumably shows its context engine working.
- Swapping `search_schema`'s keyword matching for embeddings once a schema is
  large enough that keyword overlap stops being a good relevance signal (dozens+
  of tables, ambiguous naming) — the tool contract doesn't change, only what's
  behind it.
- A caching/diffing layer so a long agent session doesn't re-pay full token cost
  for schema it already retrieved earlier in the same session, only the delta.
- Extending the same 5-tool contract to the other listed data sources (Redshift,
  Snowflake, Synapse, BigQuery) — each needs its own introspection module
  (different system catalogs/information_schema quirks) but the same interface.

**B. What major UI issues do you dislike, and how do you think they annoy current users?**

*The UI, honestly, looks almost identical to VS Code and I think that's a missed opportunity
more than a safe choice. VS Code forks are common, but the ones that stand out have a visual
identity of their own, not just a different logo on the same shell the way PyCharm feels distinct
from VS Code even though both are IDEs. I'd invest in giving Superbrain its own visual
language, something that signals “this is a different way of working,” not “this is VS Code with
an AI panel.”
Beyond looks, I think the bigger opportunity is becoming a genuinely centralized workspace
not just for writing code, but for the whole path from data to product: data transformation,
BI/analytics building, and app building and deployment, all inside one place. Right now that
work is scattered across separate tools, and every handoff between them is friction and
context loss. If Superbrain became the place developers default to for that entire loop instead
of just the coding step, it stops being “yet another AI IDE” and becomes the tool people build
their whole workflow around.*

---

## What I built and why

*Before writing any code, I spent time going through the Superbrain IDE and researching what
makes it different from other coding assistants like Codex and Claude Code. The core
differentiator I found was Token Fold the technique behind the claimed 60–80% token
reduction. But going through it, I noticed a trade-off: relative to Codex and Claude Code,
Superbrain seemed to fall slightly behind on correctness the ability to get things right without
as many back-and-forth attempts likely a consequence of operating with less context.
That felt like the real gap worth exploring. Coding agents build code iteratively: generate, check
syntax, check logical correctness, loop back if something's wrong. Every failed loop costs
tokens and time. If the agent already has the right context up front specifically, the schema of
whatever data platform it's working against a lot of those failed loops shouldn't happen in the
first place.
So instead of compressing everything and hoping the model infers what it needs, I wanted to
equip the agent with tools to retrieve exactly the schema context it needs, when it needs it.
That's the gap the POC explores: give the agent narrow, on-demand access to database
schema, so it has enough context to be accurate early, without paying the token cost of
dumping the whole schema up front reducing cost and reducing the number of failed
iterations at the same time.*

## Decision-making log

*I spent about a day researching before writing any code going through Superbrain, reading
about Token Fold, and comparing it against Codex and Claude Code to understand where the
actual gap was, before deciding what to build.
On the stack: I'm primarily a Python developer, and my default for building MCP servers is
FastMCP. For this project, though, I stuck with a single TypeScript/Next.js stack instead of a
separate Python FastMCP service talking to a Next.js frontend. Two languages means two
runtimes and a network hop between them more moving parts to keep in sync for what's
meant to be a focused POC. A same-process MCP server inside the Next.js app avoided that
overhead entirely, and is also faster than an inter-process call out to a separate FastMCP
service would have been.
The core product decision was to build one feature end to end progressive schema retrieval
for iterative query-building loops properly, and be upfront in the UI that the rest of the shell
(Explorer, Search, Source Control, Run, Extensions) is unwired placeholder, rather than
spreading effort thin faking a full IDE.*

## Wanna Try?
 *Live Application Link.* - https://ide-dataplatform-conn-feat-demo-hg0unkaz8.vercel.app/