OntoBoom Docs
OntoBoom turns your domain model into an agent contract: a versioned bundle of OWL/RDF ontology + database mapping + AI tool schema + SHACL validation + SHA-256 manifest. The four stages — design → publish → deploy → connect — match the layout below. Publish and deploy are independent; you can do either, both, or neither.
Quickstart
- Sign up at ontoboom.com/register. Free plan: 1 project, 1 ontology, 5 AI Copilot credits.
- Create a project. Either fork a curated pack from hub.ontoboom.com/@ontoboom (crm, e-commerce, fintech, b2b-saas, healthcare-lite, customer-360) or start with your own database.
- Capture your schema — Database tab → add connection → snapshot.
- Map schema to ontology — Mapping tab → auto- suggest + manual fixes.
- Export the OPS package — Deploy tab → ZIP with ontology.ttl + mapping.json + tool-schema.json + shapes.ttl + ops.json.
- Publish the ontology to Hub (optional) — shares the semantic model, without your mappings or credentials. Serves the schema over MCP.
- Deploy to Runtime (optional) — Deploy tab → Deploy to Cloud. Gives you a live MCP endpoint that answers questions from your own database, not just the schema. See Deploying to Runtime.
- Wire to your agent using one of the framework sections below.
Publish and Deploy are different things, and you can do either, both, or neither. Publishing shares the ontology — a portable model with no credentials in it. Deploying ships the OPS package — that same ontology plus your mapping rules and database connection — so an agent can ask questions and get rows back.
1 · Design
Designing the ontology
The Studio editor at app.ontoboom.com is where the ontology actually gets built. You can start from scratch, fork a curated @ontoboom pack from the Hub, or reverse-engineer from a database snapshot — pick whichever matches your team's starting point.
The canvas
React-Flow-based visual graph editor. Drag elements from the left palette onto the canvas, drag from a class's edge to create a relationship. Selecting a node opens the Inspector panel where you set the IRI, label, comment, SHACL constraints, and (for object properties) characteristics like functional, inverseFunctional, transitive, symmetric.
Five element types live in the palette:
- Class — an entity type (e.g. Customer, Account, Order). Has an IRI, optional superclasses, optional
disjointWith/equivalentClassessets. - Object property — a typed relationship between two classes. Drawn as a directed edge with a label. Domain + range are inferred from the two ends but can be overridden.
- Data property — a typed attribute on a class (string, decimal, date, etc.). Edges are not drawn for these; they live in the class's inspector.
- Individual — a named instance of a class (e.g.
USDas an instance ofCurrency). Useful when an enumeration is small and stable. - SHACL Constraint — a NodeShape targeting a class with one or more PropertyShapes.
AI Copilot
Chat panel on the right of the canvas. Powered by gpt-4o-mini with structured tool calls — it doesn't just suggest text, it actually executes operations against your ontology JSON (add class, rename property, fix validation error, generate SHACL constraints). Useful prompts:
- "Add a Person class with name and email properties."
- "Create a relationship: Order placedBy Customer."
- "Fix the validation errors below." — pair this with the validation panel which auto-feeds error context into the prompt.
- "Add SHACL constraints to enforce email format on Person."
Each Copilot turn consumes 1 AI Credit (Free includes 5/mo; Pro and Teams include 5/mo with the option to purchase more from the profile page).
Subject areas
Visual grouping for large ontologies. Each class can belong to zero or more subject areas, each rendered as a colored background region on the canvas. Use them to keep a 50-class ontology legible (customer area, billing area, fulfilment area, etc.).
Imports — composing across the Hub
The Imports panel in the editor lets you declare a semver-pinned dependency on another Hub ontology. Type a Hub-search query, pick a result, set a constraint (e.g. ^1.0), and the imported entities show up as ghost nodes you can use as relationship targets without owning them. The imports list is persisted in the ontology JSON as a top-level imports[] array and travels with the publish — downstream consumers see your declared deps in the Hub UI.
SHACL validation in real time
The bottom Validation panel runs constraint checks continuously as you edit. Errors include the path (which class / property is wrong), a one-line description, and a Fix with Copilot button that pipes the errors into the Copilot prompt. Constraints you can express today:
- Cardinality: minCount, maxCount
- Data type: xsd:string, xsd:integer, xsd:decimal, xsd:date, xsd:dateTime, xsd:boolean, etc.
- Value enumeration:
sh:inwith a list of allowed values - Regex pattern:
sh:pattern(e.g. email, E.164 phone, ISO currency code) - Numeric range: minInclusive / maxInclusive / minExclusive / maxExclusive
- String length: minLength / maxLength
- Object-property class target:
sh:class— restrict an edge to instances of a specific class
Versioning
Every save is a new OntologyVersion row. The version selector in the toolbar lets you switch between versions, compare diagrams, or roll back by selecting an older version and saving it forward. Team projects also support soft locking: when a member opens an ontology, others see "Locked by Alice — read-only" and can request the lock when she's done.
Export formats
Any saved version exports to:
- Turtle (.ttl) — canonical OWL/RDF serialization, what
ontology.ttlin the OPS package contains - JSON-LD (.jsonld) — RDF in JSON syntax, good for web APIs
- RDF/XML (.rdf) — legacy enterprise tools
- OntoBoom JSON (.json) — the native editor format with diagram layout preserved
- Cypher (.cypher) — node + relationship statements for loading into Neo4j or any property-graph DB
When you're happy with the model, the next two sub-sections cover how to attach it to a real database (Database connectors) and what gets bundled into the deployable OPS package.
Database connectors
Ten dialects are supported. Connection credentials are encrypted at rest with Fernet (key in DB_CREDENTIALS_ENCRYPTION_KEY). Alternatively, import a DDL file (any database that can exportCREATE TABLE SQL) — no live connection required.
- PostgreSQL — host, port (5432), database, schema, user, password
- MySQL / MariaDB — host, port (3306), database, user, password
- SQL Server — host, port (1433), database, schema, user, password
- Oracle — host, port (1521), service name, schema (owner), user, password
- SQLite — file path only
- Amazon Redshift — host, port (5439), database, schema, user, password
- Snowflake — account identifier, database, schema, user, password, warehouse (optional), role (optional)
- BigQuery — project ID, dataset, service account JSON
- Databricks — workspace hostname, catalog, schema, HTTP path, personal access token
- MongoDB — host, port (27017), database; schema inferred by sampling documents
After connection:
- Capture snapshot — Studio ingests the table names, column types, and foreign keys.
- Reverse-engineer to ontology — generates a starter ontology with classes per table and data properties per column. You then refine in the canvas.
- Auto-map — deterministic name matching plus AI suggestions. Each rule has a confidence score and a one-line reasoning string you can review.
Mapping schema to ontology
Once you have an ontology in step 1 and a database snapshot in step 2, mapping is the bridge: a set of rules that says "column X in table Y means concept Z in the ontology." This is the artifact that makes semantic_query possible — without it, agents would still have to guess column names and joins.
The three rule target types
Each row in mapping.json is one rule. Every rule has the same shape but targets one of three ontology element types:
- class — the whole table maps to a class.
source_columnisnull. Example: tablecustomersmaps to classCustomer. - data_property — a single column maps to a data property (a typed attribute) on a class. Example:
customers.emailmaps to the data propertyemailAddressonCustomer. - object_property — a foreign-key column maps to a typed relationship between two classes. Example:
orders.customer_idmaps to the object propertyplacedByfromOrdertoCustomer.
The Mapping tab — what you actually do
Open the Mapping tab on a project that has (a) at least one ontology and (b) a captured database snapshot.
- Auto-suggest — click the button at the top of the Mapping tab. Studio uses deterministic name matching (table name ≈ class label, column name ≈ property label) and the AI Copilot to propose rules. Each proposal lands in the rule list with a confidence score (0.0–1.0) and a reasoning string explaining the match. You don't have to accept any of them.
- Review + accept — each row in the rule list has Accept / Reject / Edit buttons. Reject removes the suggestion; Accept commits it. Edit opens the rule for adjustment.
- Add manual rules — for joins the auto- matcher misses (denormalised columns, JSON fields, etc.), click New rule, pick the source table / column, pick the ontology target, choose the rule type, save. Manual rules get confidence 1.0 by convention.
- Save as version — every save creates a new
MappingVersionrow. Older versions stay accessible via the version selector at the top of the tab. The latest version is what the Export tab bundles and the Playground tab queries against.
What a rule looks like (mapping.json)
{
"rules": [
{
"source_table": "customers",
"source_column": null,
"target_type": "class",
"target_iri": "https://example.org/sales#Customer",
"target_label": "Customer",
"confidence": 0.95,
"reasoning": "Table 'customers' maps to class Customer by name + plural-singular match."
},
{
"source_table": "customers",
"source_column": "email",
"target_type": "data_property",
"target_iri": "https://example.org/sales#emailAddress",
"target_label": "email address",
"confidence": 0.92,
"reasoning": "Column 'email' matches data property emailAddress by label similarity."
},
{
"source_table": "orders",
"source_column": "customer_id",
"target_type": "object_property",
"target_iri": "https://example.org/sales#placedBy",
"target_label": "placed by",
"confidence": 0.87,
"reasoning": "FK orders.customer_id -> customers.id matches placedBy: Order -> Customer."
}
]
}The source block in the same JSON carries the dialect (postgres / mysql / mssql) and default schema, so the LLM that turns a question into SQL knows exactly how to qualify table names.
Why this matters at query time
When an agent calls semantic_query("customers with active subscriptions"), the rule list is included verbatim in the system prompt to the LLM that generates the SQL. Every concept the question mentions ("customer", "active subscription") maps to a row in the rule list, which maps to a concrete schema.table.column reference. The model doesn't have to invent column names — it just composes joins from the rules it's been handed.
That's the entire premise: well-mapped ontology + well-mapped schema = an agent that queries your data accurately, with the real column names and joins.
Common mapping patterns
- One row, one entity: a table whose primary key identifies a unique instance — map the table to a class, then map each column to a data property.
- Foreign keys: a column ending in
_idthat points at another table — map the column as an object property from the source class to the target class. - Join tables: a table with two FKs and no other data — map both FKs as object properties from the join-table class, OR (more often) model the join table as a many-to-many relationship between the two endpoint classes and skip mapping the join table itself.
- Polymorphic / discriminator columns: a
typecolumn that switches subtype — map the type column tordf:typein the manual rule editor and create one class per discriminator value. - Materialized views: mappable just like tables. Good for denormalising complicated joins so the mapping rule list stays simple.
- JSON columns: Postgres
jsonbkeys can be mapped using a JSON path in the column field (address->>'street'); the LLM will use it verbatim in generated SQL.
The OPS package
OPS stands for Ontology-Package Specification — a portable bundle that pairs your ontology with database-to-ontology mappings and an AI-ready tool schema. It's what makes OntoBoom an agent tool, not just an ontology editor. Five files, one zip:
ontology.ttl
Your OWL ontology in Turtle. Load it into Protege, Apache Jena, rdflib, or any SPARQL endpoint.
mapping.json
OBS-Mapping v1.0. Each rule maps a database element to an ontology concept:
{
"source": {"dialect": "postgres", "schema": "public"},
"rules": [
{
"source_table": "accounts",
"source_column": null,
"target_type": "class",
"target_iri": "https://example.org/finance#Account",
"target_label": "Account",
"confidence": 0.95,
"reasoning": "Table accounts maps to class Account by name + semantics."
},
{
"source_table": "accounts",
"source_column": "balance",
"target_type": "data_property",
"target_iri": "https://example.org/finance#balanceAvailable",
"target_label": "balance available",
"confidence": 0.88
}
]
}tool-schema.json
OBS-Tool v1.0. A JSON-schema function definition you drop into any framework that follows the convention (OpenAI, Anthropic, LangChain, Bedrock, Vertex, …). Exposes a semantic_query tool whose arguments are ontology-aware filters — not raw SQL.
shapes.ttl
SHACL constraints — cardinality, datatype, value-set enumerations, regex patterns. Validate instance data before ingesting.
ops.json
Manifest with SHA-256 + byte size per file. Use it to verify integrity after transfer or to pin a specific package version in your deploy pipeline.
Playground (preview)
The Playground tab is a live preview of what an agent will experience when it calls semantic_query against this project. Use it to sanity-check your mapping before you ship the OPS package or publish to Hub.
- Type a natural-language question into the input box at the top of the Playground tab — e.g. "customers with active subscriptions in California created in the last 30 days".
- Studio sends the question + the current mapping rules + a small system prompt to gpt-4o-mini, which produces a SQL
SELECT(alwaysLIMIT 100, never a mutating statement). - Studio executes the SQL against the connected database from step 2 and renders the result — the generated SQL on top, the column headers and row data underneath.
- Iterate — if the SQL is wrong (referenced an unmapped column, picked the wrong join), the fix is almost always to add or correct a mapping rule, not to re-prompt the LLM. Go back to the Mapping tab, fix the rule, save, return.
Playground consumes 1 AI Credit per query (same accounting as Copilot). It's your loop-closer before exporting or publishing — if Playground returns the right answer, your agent will too, because they use the same semantic_query implementation.
SHACL validation
Validate agent output (or any external data) against shapes.ttl before ingesting it into a production graph:
from pyshacl import validate
from rdflib import Graph
data_graph = Graph().parse("instance-data.ttl", format="turtle")
shapes_graph = Graph().parse("shapes.ttl", format="turtle")
conforms, _, report = validate(
data_graph,
shacl_graph=shapes_graph,
inference="rdfs", # apply RDFS subclass reasoning
)
if not conforms:
print(report) # human-readable violations
raise ValueError("Data failed SHACL validation")Constraints supported in OntoBoom-generated shapes: cardinality (minCount, maxCount), datatype, enumeration (sh:in), regex pattern, numeric range, string length, and object-property class targets.
2 · Publish
Publishing to Hub
From the Studio editor toolbar, click Publish to Hub. The modal pre-fills:
- Namespace — your auto-provisioned
@your-handle(or another namespace you own). - Slug — derived from the ontology name, kebab-case. Locked after first publish.
- Version — next patch above the latest published. Bump major/minor manually in the field.
- Visibility — Private (default), Unlisted, or Public. Public requires an SPDX license.
Once published you get three URLs for the same artifact:
https://hub.ontoboom.com/@ns/slug— Hub UI pagehttps://api.ontoboom.com/hub/v1/ontologies/@ns/slug@x.y.z— JSON pullhttps://mcp.ontoboom.com/o/@ns/slug@x.y.z— live MCP endpoint
Versions are immutable. Retire a buggy version with yank, not delete — the record stays so downstream consumers see a clear signal.
Three visibility levels. Public: discoverable in Hub search, served anonymously over MCP, indexable by search engines. Unlisted: not enumerated in search, but anyone with the URL reads + serves over MCP. Private: only the namespace owner can read; MCP requires a Bearer obt_ token (see below).
3 · Deploy
Publishing to Hub shares your ontology and serves its schema. Deploying to Runtime ships the whole OPS package — ontology, mapping rules and the database connection — and gives agents an endpoint that answers questions with rows from your own database. The two are independent: deploy without ever publishing if you want.
Deploying to Runtime
Open your project, go to the Deploy tab, and click Deploy to Cloud. You choose:
- Mapping version — the deployment is pinned to it. Editing mappings afterwards does not change a running runtime until you redeploy.
- Ontologies — which of the project's ontologies the agent can see.
- SHACL shapes — include constraints so agents can see what valid data looks like.
You get a stable endpoint that does not change when you redeploy:
https://api.ontoboom.com/runtime/{runtime-id}/mcpNothing is copied. The runtime stores pointers to your mapping version and ontologies, not a snapshot of your data. Every question runs a fresh, read-only query against your database at request time, so answers are never stale and no second copy of your data exists anywhere.
Runtime vs. Hub MCP serving. Both speak MCP, and they answer different questions:
mcp.ontoboom.com/o/@ns/slug@ver— the published ontology. Describes what your concepts mean. Schema only, no data, immutable per version.api.ontoboom.com/runtime/{id}/mcp— a deployed OPS package. Describes the concepts and answers with live rows. Mutable — redeploy any time.
Runtime tools
A runtime exposes three MCP tools:
semantic_query(query, max_rows)— ask in plain English. The runtime translates the question into SQL using your ontology and mapping rules, runs it, and returns the rows.list_entities()— every concept in the deployed ontology.describe_entity(name)— one concept in detail: its attributes, its relationships to other concepts, and any SHACL constraints.
Read-only, enforced in code. semantic_query rejects any statement that is not a SELECT — checked after stripping comments, so it cannot be talked around by a prompt. Queries time out after 30 seconds and return at most 100 rows.
Calling it directly, without an agent:
curl -sS -X POST https://api.ontoboom.com/runtime/{id}/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer obt_YOUR_TOKEN" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "semantic_query",
"arguments": { "query": "Which customers opened accounts last month?" }
}
}'There is also an unauthenticated health check, useful for monitoring. It reports status and auth mode but never touches your data:
curl https://api.ontoboom.com/runtime/{id}/mcp/healthSecuring a runtime
Each runtime is either token or public. New runtimes default to token. Switch modes on the Runtimes page.
- Token — callers must send an API token that has access to the runtime's project. Create one under API Tokens. Deleting the token cuts access immediately.
- Public — anyone with the URL can query the database behind it. The URL is the only credential, and there is no way to revoke it short of deleting the runtime. Use this only for demos on data you would publish anyway.
In token mode, send the key as a bearer token:
Authorization: Bearer obt_your_token_hereClaude Desktop. The “Add custom connector” dialog has no field for a header, and its OAuth fields do not apply here — leave them empty. To pass a token, edit claude_desktop_config.json and route through mcp-remote, which can attach one:
{
"mcpServers": {
"banking": {
"command": "npx",
"args": [
"-y", "mcp-remote@latest",
"https://api.ontoboom.com/runtime/{id}/mcp",
"--header", "Authorization: Bearer obt_YOUR_TOKEN"
]
}
}
}A public runtime needs none of that — name and URL in the connector dialog is enough.
LangChain / LangGraph passes headers directly:
from langchain_mcp_adapters.client import MultiServerMCPClient
async with MultiServerMCPClient({
"banking": {
"url": "https://api.ontoboom.com/runtime/{id}/mcp",
"transport": "streamable_http",
"headers": {"Authorization": "Bearer obt_YOUR_TOKEN"},
}
}) as client:
tools = await client.get_tools()Lifecycle & monitoring
Everything below is on the Runtimes page.
- Stop / Start — a stopped runtime returns
503and serves nothing. History and statistics are kept, and the URL is unchanged when you start it again. This is the quickest way to take an endpoint offline. - Redeploy — pin a newer mapping version or change which ontologies are exposed. The endpoint URL stays the same, so connected agents keep working.
- Delete — permanent, and the URL is gone for good.
- Test — an inline playground for asking the runtime questions from the browser. Signed in as the owner, you do not need a token for this.
Each runtime reports:
- total requests, requests in the last 24h and 7 days
- error rate and average latency over 24h
- a per-tool breakdown — which tools agents actually use
- recent activity — the last 20 calls with the question asked, latency, and any error
Recent activity shows the natural-language questions agents asked. That is useful for debugging a mapping, and it is visible only to people who can already access the project.
4 · Connect your agent
Every framework below consumes one of three things: the tool-schema.json from your OPS export, the published ontology at mcp.ontoboom.com/o/@ns/slug@ver for schema, or a deployed runtime at api.ontoboom.com/runtime/{id}/mcp for live answers from your data. Pick the path your stack already speaks.
LangChain / LangGraph
Path A — wrap your OPS package as a LangChain tool. The full semantic_query implementation auto- generated in the OPS README:
import json, psycopg2
from openai import OpenAI
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
with open("mapping.json") as f:
mapping = json.load(f)
def semantic_query(question: str, db_dsn: str) -> dict:
"""Translate a question to SQL using the OPS mapping rules and execute it."""
rules = mapping["rules"]
schema = mapping["source"].get("schema", "public")
rule_lines = []
for r in rules:
target = r.get("target_label") or r["target_iri"]
table = r["source_table"]; col = r.get("source_column") or ""
ref = f"{schema}.{table}.{col}" if col else f"table {schema}.{table}"
rule_lines.append(f" - {target} ({r['target_type']}) -> {ref}")
sql = OpenAI().chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content":
"Translate to a single SELECT with LIMIT 100.\n" + "\n".join(rule_lines)},
{"role": "user", "content": question},
],
).choices[0].message.content.strip().strip("`")
conn = psycopg2.connect(db_dsn)
cur = conn.cursor()
cur.execute(f"SELECT * FROM ({sql}) AS _q LIMIT 100")
cols = [d[0] for d in cur.description]
rows = cur.fetchall()
conn.close()
return {"sql": sql, "columns": cols, "rows": rows}
agent = create_react_agent(ChatOpenAI(model="gpt-4o-mini"), tools=[semantic_query])
agent.invoke({"messages": [(
"user", "How many investment accounts opened in the last 30 days?"
)]})Path B — connect to the live MCP endpoint via the LangChain MCP adapter. No OPS download; the published version is queried at request time.
from langchain_mcp_adapters.client import MultiServerMCPClient
from langgraph.prebuilt import create_react_agent
from langchain_openai import ChatOpenAI
async with MultiServerMCPClient({
"ontoboom": {
"url": "https://mcp.ontoboom.com/o/@ontoboom/customer-360@0.1.0",
"transport": "sse",
# for private ontologies:
# "headers": {"Authorization": "Bearer obt_your_token"},
},
}) as client:
tools = await client.get_tools()
agent = create_react_agent(ChatOpenAI(model="gpt-4o-mini"), tools=tools)
result = await agent.ainvoke({"messages": [(
"user", "List entity types in the customer-360 ontology"
)]})OpenAI function calling
tool-schema.json is already shaped for OpenAI — just unwrap the tools array:
import json
from openai import OpenAI
with open("tool-schema.json") as f:
schema = json.load(f)
functions = [{
"name": t["name"],
"description": t["description"],
"parameters": t["parameters"],
} for t in schema["tools"]]
response = OpenAI().chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content":
"Find customers with active subscriptions in California"}],
functions=functions,
)
fc = response.choices[0].message.function_call
print(fc.name, fc.arguments)Anthropic SDK (Claude API)
Two integration paths with Claude — direct tool use, or via an MCP server connection. Direct tool use:
import json, anthropic
with open("tool-schema.json") as f:
schema = json.load(f)
# Anthropic's tools format is nearly identical to OpenAI's
tools = [{
"name": t["name"],
"description": t["description"],
"input_schema": t["parameters"],
} for t in schema["tools"]]
resp = anthropic.Anthropic().messages.create(
model="claude-opus-4-7",
max_tokens=1024,
tools=tools,
messages=[{"role": "user",
"content": "Pull customers who opened a support ticket this week"}],
)MCP via the official Python MCP SDK:
from mcp import ClientSession
from mcp.client.sse import sse_client
async with sse_client(
"https://mcp.ontoboom.com/o/@ontoboom/customer-360@0.1.0",
headers={"Authorization": "Bearer obt_your_token"}, # only for private
) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
result = await session.call_tool(
"describe_entity", {"name": "SupportTicket"}
)
print(result)AWS Strands Agents
Strands is Anthropic + AWS's open-source agent SDK. It has native MCP support, so the OntoBoom endpoint plugs in directly:
from strands import Agent
from strands.tools.mcp import MCPClient
from mcp.client.sse import sse_client
mcp = MCPClient(lambda: sse_client(
"https://mcp.ontoboom.com/o/@ontoboom/crm@0.1.0",
))
with mcp:
agent = Agent(
model="us.anthropic.claude-opus-4-7-v1:0", # Bedrock model id
tools=mcp.list_tools_sync(),
)
agent("Which Opportunity stages are defined in this ontology?")GCP Vertex AI Agent Builder
Vertex AI Agent Builder consumes function declarations on the Gemini API. Convert tool-schema.json:
import json
from vertexai.generative_models import (
GenerativeModel, Tool, FunctionDeclaration,
)
with open("tool-schema.json") as f:
schema = json.load(f)
declarations = [
FunctionDeclaration(
name=t["name"],
description=t["description"],
parameters=t["parameters"],
)
for t in schema["tools"]
]
model = GenerativeModel(
"gemini-2.5-pro",
tools=[Tool(function_declarations=declarations)],
)
resp = model.generate_content(
"Customers who churned in Q3 with LTV above 5000"
)
fc = resp.candidates[0].content.parts[0].function_call
print(fc.name, dict(fc.args))For Agent Engine deployment, register the function as a reasoning-engine tool — same JSON-schema parameters, same tool name.
Azure AI Foundry
Foundry Agents accept function tools whose parameters are JSON Schema — identical shape to tool-schema.json:
import json
from azure.ai.agents import AgentsClient
from azure.identity import DefaultAzureCredential
with open("tool-schema.json") as f:
schema = json.load(f)
tools = [{
"type": "function",
"function": {
"name": t["name"],
"description": t["description"],
"parameters": t["parameters"],
},
} for t in schema["tools"]]
client = AgentsClient(
endpoint="https://<your-project>.services.ai.azure.com",
credential=DefaultAzureCredential(),
)
agent = client.create_agent(
model="gpt-4o-mini",
name="ontoboom-semantic-query",
instructions="Use semantic_query to answer questions about the domain.",
tools=tools,
)For MCP-style integration, Foundry's upcoming MCP server support consumes the same mcp.ontoboom.com/o/@ns/slug@ver URL.
CrewAI
Tool wrapper around semantic_query:
from crewai import Agent, Task, Crew
from crewai_tools import tool
# semantic_query as defined in the LangChain section above
@tool("Semantic query")
def semantic_query_tool(question: str) -> str:
"""Answer questions about the domain by translating them
to SQL using the OntoBoom OPS mapping and executing them."""
result = semantic_query(question, db_dsn=DB_DSN)
return str(result)
analyst = Agent(
role="Data Analyst",
goal="Answer questions about customer behaviour grounded in the ontology",
tools=[semantic_query_tool],
)
crew = Crew(
agents=[analyst],
tasks=[Task(
description="How many trial customers converted last month?",
agent=analyst,
expected_output="A number with the SQL that produced it.",
)],
)
crew.kickoff()CrewAI also supports MCP via crewai_tools.MCPServerAdapter; pattern matches the LangChain MCP block above with the same mcp.ontoboom.com/o/@ns/slug@ver URL.
Claude Desktop / Cursor (no-code MCP)
For end-user tools that speak MCP natively, paste the endpoint URL into the client config. Claude Desktop → ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"ontoboom-crm": {
"url": "https://mcp.ontoboom.com/o/@ontoboom/crm@0.1.0",
"transport": "sse"
}
}
}Cursor → .cursor/mcp.json:
{
"servers": [
{
"url": "https://mcp.ontoboom.com/o/@ontoboom/crm@0.1.0",
"transport": "sse"
}
]
}Restart the client; MCP tools appear in the tool tray.
Shell test of any MCP endpoint:
curl https://mcp.ontoboom.com/o/@ontoboom/crm@0.1.0/health
curl -sS -X POST https://mcp.ontoboom.com/o/@ontoboom/crm@0.1.0 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
curl -sS -X POST https://mcp.ontoboom.com/o/@ontoboom/crm@0.1.0 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"describe_entity","arguments":{"name":"Account"}}}'Tools exposed today: list_entities, describe_entity. Both are derived from the manifest at request time, so they always reflect the published version.
Private MCP via Bearer obt_ token
Anonymous traffic only sees Public + Unlisted ontologies. To serve a Private ontology over MCP, include a Bearer token from the namespace owner (mint one at profile → API tokens):
# curl
curl -H "Authorization: Bearer obt_your_token_here" \
https://mcp.ontoboom.com/o/@your-handle/private-slug@1.0.0/health
# Claude Desktop config — note the headers block
{
"mcpServers": {
"ontoboom-private": {
"url": "https://mcp.ontoboom.com/o/@your-handle/private-slug@1.0.0",
"transport": "sse",
"headers": {
"Authorization": "Bearer obt_your_token_here"
}
}
}
}The token must belong to the namespace owner (or an admin). Token-scope-by-project does not apply here — Hub serving is namespace-gated, not project-gated.
Reference
Public REST API
Programmatic access uses Bearer tokens (prefix obt_). Generate one in your profile → API tokens. Token is shown once on issuance; only the hash is stored.
curl https://api.ontoboom.com/api/v1/projects \
-H "Authorization: Bearer obt_your_token_here"
curl https://api.ontoboom.com/api/v1/ontologies/<uuid> \
-H "Authorization: Bearer obt_your_token_here"Full reference (OpenAPI/Swagger): api.ontoboom.com/api/v1/docs.
OntoBoom MCP Server
OntoBoom ships a built-in Model Context Protocol server at https://api.ontoboom.com/mcp/. It lets any MCP-compatible agent or IDE work directly with your ontologies — run the OWL 2 RL reasoner, execute SPARQL, validate SHACL constraints, and browse the public Hub registry — without leaving the agent loop.
Authentication
Every request requires a Bearer token (your obt_ API token). Generate one in Profile → API tokens.
Authorization: Bearer obt_your_token_hereAvailable tools
Your ontologies (scoped to token's project access):
list_projects— list all accessible projectslist_ontologies(project_id)— list ontologies in a projectget_ontology(ontology_id)— full metadata + model JSONget_classes(ontology_id)— all classes with IRIs and superclassesget_properties(ontology_id)— object and data propertiesexport_ontology(ontology_id, format)— export as turtle, jsonld, xml, or jsonsearch_classes(query)— search across all accessible ontologiesrun_reasoner(ontology_id)— OWL 2 RL inference + SHACL validation (returns inferred triples and violations)execute_sparql(ontology_id, query)— run a SPARQL SELECT/CONSTRUCT/ASK against the ontology's RDF graphvalidate_shacl(ontology_id)— SHACL-only validation without full reasoning
Hub registry (public, no project scope needed):
search_hub(query, limit)— search public ontologies by name or keywordexplore_hub(limit)— browse featured, recent, and popular ontologieslist_hub_namespace(namespace)— list ontologies under a namespace (e.g.acme)get_hub_ontology(namespace, slug, version)— get the full manifest for a Hub ontologylist_hub_versions(namespace, slug)— list all published versions
Connect from Claude Desktop
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"ontoboom": {
"url": "https://api.ontoboom.com/mcp/",
"transport": "http",
"headers": {
"Authorization": "Bearer obt_your_token_here"
}
}
}
}Connect from Cursor
// .cursor/mcp.json
{
"servers": [
{
"url": "https://api.ontoboom.com/mcp/",
"transport": "http",
"headers": {
"Authorization": "Bearer obt_your_token_here"
}
}
]
}Connect via Python MCP SDK
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async with streamablehttp_client(
"https://api.ontoboom.com/mcp/",
headers={"Authorization": "Bearer obt_your_token_here"},
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
# List tools
tools = await session.list_tools()
print([t.name for t in tools.tools])
# Run the reasoner
result = await session.call_tool(
"run_reasoner",
{"ontology_id": "your-ontology-uuid"}
)
print(result.content[0].text)
# Execute SPARQL
result = await session.call_tool(
"execute_sparql",
{
"ontology_id": "your-ontology-uuid",
"query": "SELECT ?class WHERE { ?class a owl:Class . }",
},
)
print(result.content[0].text)Quick test with curl
# List tools
curl -sS -X POST https://api.ontoboom.com/mcp/ \
-H "Authorization: Bearer obt_your_token" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
# Run the OWL 2 RL reasoner
curl -sS -X POST https://api.ontoboom.com/mcp/ \
-H "Authorization: Bearer obt_your_token" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{
"name":"run_reasoner",
"arguments":{"ontology_id":"<uuid>"}
}
}'Something missing or wrong? Open a thread at support or contact us.