What it is, and what it is not
OrionBelt® Analytics (OBA) is an MCP server that sits between an AI client and your SQL warehouse or lakehouse. It reads your schema, writes it down as an RDF/OWL ontology with the SQL needed to reach every concept, and gives the model the tools to find the right tables, join them correctly, and run the query. Every query passes a deterministic check against that ontology first.
It is
- An MCP server between your AI client and your database
- A generator of an ontology of your schema, with SQL mappings
- A schema search that finds the tables and join paths a question needs
- A rule-based check of every query before it runs
- Read-only: queries run inside your database, nothing is copied out
It is not
- A BI tool: charts appear in the conversation, your dashboards stay
- A data platform or ETL: it works on your schemas as they are
- An LLM: you bring the client and the model
- A governed metrics layer: that is the OrionBelt® Semantic Layer
- A write path: DDL and DML are refused
Architecture
Clients talk to the server over MCP (Streamable HTTP). The server talks to the database over SQL.
- GraphRAG combines a vector index of table and column descriptions with a graph of the keys between tables. Vector search decides which tables matter; graph search decides how to join them, up to 12 hops, and says so when two routes are equally short.
- Ontology. Generated from the schema as RDF/OWL with
oba:annotations and a W3C R2RML mapping, stored in an Oxigraph store and queryable with SPARQL. You can replace it with your own. - OBQC parses each statement and compares every table, column, join and aggregate with the ontology. No LLM is involved. Errors block the query; warnings travel back with the result so the model can correct itself.
- Execution enforces read-only access and bounds the result.
generate_chartturns a result into an interactive Plotly chart inside clients that render MCP Apps, or a PNG for everyone else.
Each connection keeps a workspace on disk: schema cache, ontology versions, the GraphRAG index and the RDF store. Reconnecting to the same database restores it, so a known database is ready without another discovery.
A typical session
“Connect to our sales database. Which customer regions grew revenue last quarter, and how do their returns compare?”
- Connect. The model lists the configured databases and connects to the one you named:
list_databases,connect_database(database="sales"). A known workspace is restored. - Discover.
discover_schemareads tables, keys and views; the GraphRAG index builds in the background. - Model.
generate_ontologywrites the ontology.suggest_semantic_namesandapply_semantic_namesgive cryptic columns business names. Every later question is matched against those names too, so "revenue" findsnet_amt. - Ask.
graphrag_query_contextreturns the relevant tables, columns and join paths in one compact answer. For a question across two fact tables,plan_composite_queryproposes a fan-trap-safe shape. - Check, run, chart.
execute_sql_queryruns OBQC, then the query, read-only.generate_chartdraws the result.
The example question is deliberately a two-fact one. Revenue and returns live in different tables, and summing both across a one-to-many join inflates the totals. OBQC blocks that query and points to the fix: aggregate each fact first, then combine. If the model insists on running it anyway, a client that can ask the user does so, naming the tables, before any inflated number is shown.
Bring your own ontology
The generated ontology is a starting point. When your layer declares no keys, or you already maintain a domain model, you can supply your own.
- Start. Download the generated ontology with
download_artifact, or start from one you have. - Edit. Add joins, business names and descriptions in OrionBelt® Ontology Builder or any OWL editor.
- Upload. Drop the
.ttlfile into the chat, or place it in the server's import folder;load_my_ontologyreads it. - Activate. It becomes the active ontology when it maps classes and properties to the database with
oba:annotations. If it does not, it is still loaded for SPARQL, the previous ontology stays in force, and the response lists what is missing. Conformance to the OBA SHACL shapes is reported as advice. - Ask. Your joins now guide the SQL, and OBQC checks every query against your model.
- Verify. Check the joins that matter against the data with
validate_relationship. The verdict (confirmed, partial, refuted, or a target that is not unique) is written onto the relationship in the ontology, and join paths show it from then on.
An uploaded ontology applies to your session only. Colleagues on the same database keep theirs, and the database itself is never changed. The most recently activated ontology wins, so generating a new one or applying business names afterwards replaces the upload. The full story, including joins inferred from column names and informational key constraints, is on Join Discovery Without Declared Keys. The annotation vocabulary is published at the oba: namespace.
Tools
OBA exposes 30 MCP tools. Each carries the standard MCP tool annotations (readOnlyHint, destructiveHint, openWorldHint), so a client or an approval layer can treat tools by what they do. None is open-world: each acts only on the configured database and the server's workspace.
| Group | Tools |
|---|---|
| Connection and schema | list_databases, connect_database, list_schemas, discover_schema, get_table_details, reset_cache, cleanup_workspace, cleanup_old_versions |
| Ontology and names | generate_ontology, suggest_semantic_names, apply_semantic_names, add_semantic_context, load_my_ontology, validate_relationship, download_artifact |
| GraphRAG | graphrag_search, graphrag_query_context, graphrag_find_join_path, reachable_from, measurable_from, plan_composite_query |
| Query and charts | sample_table_data, execute_sql_query (with OBQC), generate_chart |
| SPARQL and RDF | store_ontology_in_rdf, query_sparql, add_rdf_knowledge |
| Semantic models | save_semantic_model, get_semantic_model, list_semantic_models |
Parameters, return values and examples are in the tools reference.
Databases
Eight SQL engines, cloud and on-premises: PostgreSQL, MySQL, Snowflake, ClickHouse, Dremio, BigQuery, DuckDB/MotherDuck and Databricks SQL. SQL is parsed per dialect, so OBQC and the row limit follow each engine's own syntax.
Join discovery works best when primary and foreign keys are declared in the catalog. Many lakehouse layers declare none; see Join Discovery Without Declared Keys for the three ways around that.
Install and connect
Docker
The image on Docker Hub includes both embedding models GraphRAG can use, English and multilingual, so it runs in networks without internet access. Workspaces live in /data. Set the two -e values explicitly, or remove them from your .env: a .env copied from the repository's template sets MCP_SERVER_HOST=localhost and OUTPUT_DIR=tmp, which would make the published port unreachable and keep workspaces outside the volume.
docker run -d --name oba -p 9000:9000 \
--env-file .env \
-e MCP_SERVER_HOST=0.0.0.0 \
-e OUTPUT_DIR=/data \
-v oba-data:/data \
ralforion/orionbelt-analytics
From source
git clone https://github.com/ralforion/orionbelt-analytics
cd orionbelt-analytics
uv sync
cp .env.template .env # add your database settings
uv run server.py # http://localhost:9000/mcp
Connect a client
# Claude Code
claude mcp add --transport http orionbelt-analytics http://localhost:9000/mcp
Claude Desktop connects through mcp-remote; LangChain, OpenAI Agents SDK, CrewAI, Google ADK, Vercel AI SDK and n8n connect to the same endpoint and discover every tool. Runnable examples are in the integrations guide. OrionBelt® Chat connects to OBA and the Semantic Layer at once.
Configuration
The server reads its settings from the environment or a .env file. Database credentials live only there; no tool takes them as a parameter.
Named databases
One server can hold several databases, each under the name people use and a description in their words. The model lists them with list_databases and connects by name; if two fit, it asks. Hosts, users and tokens are never shown.
OBA_DATABASES=finance-2025,sales
DB_FINANCE_2025_TYPE=databricks
DB_FINANCE_2025_DESCRIPTION=Finance actuals 2025: GL, cost centres, budgets
DB_FINANCE_2025_DATABRICKS_CATALOG=finance
DB_FINANCE_2025_DATABRICKS_SCHEMA=gold
DB_SALES_TYPE=databricks
DB_SALES_DESCRIPTION=Orders, customers and returns
DB_SALES_DATABRICKS_CATALOG=sales
DB_SALES_DATABRICKS_SCHEMA=gold
# Shared by both connections
DATABRICKS_SERVER_HOSTNAME=adb-1234567890.12.azuredatabricks.net
DATABRICKS_HTTP_PATH=/sql/1.0/warehouses/abc123
DATABRICKS_ACCESS_TOKEN=dapi...
A setting a named database does not define falls back to the unprefixed one, so two catalogs can share one endpoint and token. With a single database configured, connect_database() needs no argument. Each database keeps its own workspace, identified by where it points and who it signs in as.
For users who ask in a different language than the schema is named in, set GRAPHRAG_EMBEDDING_MODEL=multilingual; see GraphRAG Schema Discovery.
Transport, embedding model, workspace retention, session timeouts and per-engine notes are in the configuration reference.
Security model
- Read-only SQL. Only
SELECTand schema introspection run; write and DDL statements are refused before they reach the database. - Bounded results. A row limit is applied to the parsed statement in the engine's own syntax, and the driver never fetches more than one row past it. The maximum is 5,000 rows.
- Credentials on the server. They are read from the server's environment and never pass through the conversation.
- Session isolation. Each session keeps its own schema selection and ontology state. Sessions on the same database share the connection, schema cache, GraphRAG index and RDF store. This is workflow isolation, not access control: every client uses the server's database credentials.
- No federated SPARQL. A
SERVICEclause would make the server fetch from an arbitrary endpoint, so it is refused. - Confirmation before deletion. Where the client supports elicitation,
cleanup_workspaceasks the user to confirm before it removes a connection's ontologies, RDF store and saved models.
There is no built-in user sign-in today. Run the server inside your network, next to the data, or behind your gateway.
Reference and vocabulary
| Topic | Where |
|---|---|
| GraphRAG, explained | GraphRAG Schema Discovery |
| Query checks and fan-traps | OBQC: Ontology-Based Query Check |
| Joins without keys, your own ontology | Join Discovery Without Declared Keys |
The oba: vocabulary | Namespace page · oba.ttl · SHACL shapes · example |
| Tool parameters | docs/tools-reference.md |
| Configuration | docs/configuration.md |
| OBQC rule reference | docs/obqc.md |
| Fan-trap patterns | docs/fan-trap-prevention.md |
| Changes per release | CHANGELOG.md |
OBA pairs with the OrionBelt® Semantic Layer: what OBA discovers can be saved as an OBML model, which the Semantic Layer compiles into governed, reusable metrics. Ad-hoc questions stay with OBA; recurring ones move to the model.
OrionBelt® Analytics is licensed under the Business Source License 1.1 (BUSL-1.1) and converts to the Apache License 2.0 on 2030-03-16.
Frequently Asked Questions
Is OrionBelt Analytics a BI or dashboard tool?
No. It answers questions in the conversation and can chart each answer there. Your existing dashboards stay where they are. For governed, reusable metric definitions, use its sibling, the OrionBelt® Semantic Layer.
Does it copy data out of my warehouse?
No. Queries run inside your database with the credentials configured on the server, and only bounded result sets come back. Write and DDL statements are refused before they reach the database.
Which AI clients work with it?
Any client that speaks MCP over HTTP: Claude Desktop, Claude Code, OrionBelt® Chat, LibreChat, and agent frameworks such as LangChain, OpenAI Agents SDK, CrewAI, Google ADK, Vercel AI SDK and n8n. ChatGPT custom GPTs connect through an MCP-to-REST bridge.
Which LLM does it use?
None of its own for writing SQL. You bring the client and the model. The server runs one small local embedding model to search the schema by meaning: all-MiniLM-L6-v2 by default, or a multilingual model for questions in another language than the schema. Both ship inside the Docker image, so nothing leaves the server.
What if my lakehouse tables have no primary or foreign keys?
Joins are inferred from column naming patterns and marked with a confidence. You can also upload your own ontology that states the joins, or declare informational PK/FK constraints in the catalog. Declaring keys and then adding business meaning in an ontology gives the best result. Details: Join Discovery Without Declared Keys.
Does it have user sign-in?
Not today. Deploy it inside your network or behind your gateway. The database is reached with credentials configured on the server, and every session uses them. Sessions keep their own ontology state, which is workflow isolation rather than access control.
How is it licensed?
Under the Business Source License 1.1 (BUSL-1.1). The licensed work converts to the Apache License 2.0 on 2030-03-16. For commercial licensing, contact licensing@ralforion.com.