grane

grane

Enables MCP-compatible agents to run governed, read-only analytics queries against Postgres using predefined metrics and dimensions, with safety checks and provenance on every result.

Category
Visit Server

README

Grane

Governed analytics and controlled exploration for AI agents.

Connect your database, define the business metrics that matter, and give any MCP-compatible agent governed access to those definitions — plus permissioned exploration of everything else.

Self-hosted. Deterministic. Semantic-first, not semantic-only.

Your AI can write SQL. That doesn't mean it knows what Revenue means. Grane tells it which numbers are authoritative and which conclusions are exploratory.


What Grane does

AI agents can already write SQL. But your database does not know your company's approved definitions of Revenue, MRR, Active Customer or ARPU — and letting an LLM invent them produces plausible-looking, wrong numbers.

Grane sits between your database and your agents:

Claude / ChatGPT / Cursor / internal agents
                 |
                 |  MCP
                 v
              GRANE          metrics, dimensions, relationships,
                 |           deterministic compiler, validation,
                 |  SQL      join/grain safety, provenance
                 v
           Your Postgres
  • The agent reasons. Grane enforces truth — and labels exploration. Agents send semantic requests ("revenue by country last month"); Grane resolves the approved definitions, plans the joins, compiles the SQL, and executes it read-only. Permitted raw warehouse columns can be requested as raw_dimensions / raw_metrics without writing SQL.
  • Fan-out safety. Grane knows relationship cardinality and metric grain. Measures across one_to_many joins are pre-aggregated deterministically; queries that would silently multiply rows are refused — including exploratory ones.
  • Refusal is a trust feature. Ask for a metric that isn't defined and Grane returns a structured undefined_metric response with suggestions — it never invents business logic. Raw columns are allowed only when exploration is enabled and the column is not excluded.
  • Three trust levels. governed (approved definitions only), mixed (approved metrics plus raw fields), exploratory (raw warehouse data). Agents must not present exploration as approved business truth.
  • No LLM inside. Grane is deterministic infrastructure. No API keys, no hosted data plane, nothing leaves your environment.

Connect ChatGPT, Claude, Gemini, or any MCP agent

Grane does not need your OpenAI, Anthropic, or Google API keys. You use your own agent subscription or API key on the chat side; Grane sits in the middle and answers governed analytics queries over MCP.

Your agent (ChatGPT / Claude / Gemini / Cursor)  — your LLM keys
        |
        | MCP
        v
Grane  — no LLM keys; metrics + SQL compiler
        |
        | read-only SQL
        v
Your Postgres  — DATABASE_URL

Setup in three steps:

  1. Database — point grane.yml at Postgres with a read-only user; define metrics in YAML; run grane validate.
  2. Grane MCP — run grane serve (HTTP) or let the agent launch grane serve --stdio (local desktop clients).
  3. Agent — register Grane with grane mcp connect <client> (Claude, Cursor, Gemini, VS Code, ChatGPT, Windsurf, Claude Code, or generic), then ask questions in chat.
Agent Typical setup Grane transport
Claude Desktop grane mcp connect claude stdio (local) or HTTPS (remote)
ChatGPT grane mcp connect chatgpt (prints HTTPS steps) HTTPS only — deploy Grane publicly
Gemini CLI grane mcp connect gemini stdio or HTTP
Cursor / VS Code grane mcp connect cursor or vscode stdio or local HTTP

Full walkthrough: docs/connect-an-agent.md

MCP tool reference: docs/mcp-setup.md

Warehouse connections: docs/warehouses.md

Quickstart (with the example database)

npm install -g grane-analytics @duckdb/node-api
git clone https://github.com/Nareik33L/grane.git
cd grane

# DuckDB (no Docker): seeded shop data in example/analytics-duckdb
grane -p example/analytics-duckdb validate
grane -p example/analytics-duckdb query revenue -d country --last 30d

# Or Postgres:
docker compose -f example/docker-compose.yml up -d --wait
grane -p example/analytics validate
grane -p example/analytics query revenue --dimension country --last last_month
grane -p example/analytics query revenue --raw-dimension customers.name --last 30d
grane -p example/analytics mcp doctor --offline --skip-mcp
grane -p example/analytics mcp print-config generic
grane -p example/analytics serve
# MCP  http://localhost:8080/mcp

Install

npm install -g grane-analytics
# or: npx grane-analytics --help

The CLI command is still grane. Requires Node 20+. Warehouse drivers other than Postgres are not installed with the CLI — add only the one you use (see Warehouses below). That keeps a global install free of unrelated SDK deprecation warnings.

Warehouses

Set connection.type in grane.yml. Postgres and Redshift use the bundled pg driver. Other engines need one extra package:

Type Extra install
postgres / redshift (bundled)
mysql npm install mysql2
snowflake npm install snowflake-sdk
bigquery npm install @google-cloud/bigquery
duckdb npm install @duckdb/node-api
clickhouse npm install @clickhouse/client
databricks npm install @databricks/sql

Connection examples: docs/warehouses.md

Quickstart (your own database)

grane init                 # scaffolds grane.yml, metrics.yml, dimensions.yml, relationships.yml
export DATABASE_URL=postgres://readonly_user:...@host:5432/db
grane discover             # introspect tables, columns, FKs; infer relationships
# ... define entities, metrics, dimensions, relationships ...
grane validate             # the "type checker for analytics"
grane query revenue -d country --last 30d
grane serve                # or: grane serve --stdio

Use a read-only database user. Grane also wraps every query in a READ ONLY transaction with a statement timeout, but the database remains the final security boundary.

Defining metrics

Configuration is code: YAML files, reviewed in pull requests, versioned in Git, edited by you or your coding agent.

# entities: the business objects metrics are counted at (their grain)
entities:
  order:
    table: orders
    primary_key: id

# metrics.yml
metrics:
  revenue:
    description: Net revenue from completed orders
    owner: finance
    entity: order
    type: sum                       # sum | count | count_distinct | avg | min | max | ratio
    sql: ${orders.net_amount}
    time_dimension: ${orders.completed_at}
    unit: GBP
    status: approved                # experimental | approved | deprecated
    synonyms: [sales, net sales]
    filters:
      orders.status: completed

# dimensions.yml
dimensions:
  country:
    entity: customer
    sql: ${customers.country}

# relationships.yml — cardinality powers the join-safety checks
relationships:
  orders_to_customers:
    from: orders.customer_id
    to: customers.id
    type: many_to_one

grane validate checks every reference against the live schema, verifies types, and detects unsafe fan-out before an agent ever runs a query.

The MCP surface

Four tools, deliberately hard to misuse:

Tool Purpose
catalog() Discover metrics, dimensions, entities, synonyms, and (when enabled) explorable warehouse columns
query() Run a Query Model v1 request: resolve → validate → compile → execute → provenance
validate() Dry-run a query without executing it
explain() Inspect definitions, trust level, the join plan and the exact SQL

Agents send analytical intent, not SQL:

{
  "metrics": ["revenue"],
  "dimensions": ["country"],
  "raw_dimensions": ["orders.discount_code"],
  "filters": [{ "field": "customer_type", "operator": "=", "value": "business" }],
  "time": { "from": "2026-07-01", "to": "2026-07-31", "grain": "month" },
  "order": [{ "field": "revenue", "direction": "desc" }],
  "limit": 100
}

Every result carries a trust level and provenance:

{
  "trust": "mixed",
  "governed": ["revenue"],
  "ungoverned": ["orders.discount_code"],
  "warning": "orders.discount_code is not defined in the Grane semantic model",
  "provenance": {
    "query_id": "q_1faea438cc34",
    "trust": "mixed",
    "query_model": "v1",
    "metrics": { "revenue": { "definition_version": "a82cf1d3" } },
    "generated_sql": "SELECT ...",
    "executed_at": "2026-08-25T12:00:00Z"
  }
}

See docs/connect-an-agent.md for ChatGPT, Claude, Gemini, Cursor, and grane mcp connect. See docs/mcp-setup.md for MCP tool reference and config file formats.

The trust contract

Grane is semantic-first, not semantic-only. A company should not have to model its entire warehouse before agents can investigate. Define Revenue, MRR, Customers; let agents explore discount_code or device_type when policy allows. Grane still compiles the SQL — agents never get unrestricted SQL by default.

trust Meaning
governed Every field came through an approved Grane definition. Present as business truth.
mixed Approved metrics combined with permitted raw warehouse fields. A strong lead, not an approved conclusion.
exploratory Raw warehouse data only. Investigation, not governed analytics.

Enable exploration in grane.yml:

exploration:
  enabled: true
  schemas:
    - public
  exclude:
    - users.password_hash
    - customers.ssn

Set enabled: false to refuse every raw column. Excluded columns are never queryable. The database credentials used by Grane should remain read-only.

When a raw field is repeatedly useful:

grane usage                          # orders.discount_code used in 47 analyses
grane promote orders.discount_code   # writes a governed dimension to dimensions.yml

When Grane returns trust: governed, it guarantees that every metric and dimension was explicitly defined in the semantic model, every join was known and cardinality-safe, no business logic was invented by an LLM, the SQL is inspectable, and the exact definition versions are identified. If Grane cannot safely resolve the requested meaning, it refuses instead.

What Grane is not

No dashboards, no chart builder, no built-in chatbot, no hosted data plane, no required LLM API key. Agents own presentation; Grane owns analytics truth — and always says which numbers are governed and which are exploratory.

Development

npm install
npm run test:unit                                        # no database needed
docker compose -f example/docker-compose.yml up -d --wait
npm test                                                 # unit + integration

V0.1 supports Postgres. The connector interface will open up to other databases (MySQL, ClickHouse, DuckDB, Snowflake, ...) as demand appears.

License

Apache-2.0

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured