MCP server for AI agents
@littlebigbrain/mcp is an MCP server. It
gives an agent a small set of tools over your graph. With them, an agent can:
- search by meaning,
- follow links with SPARQL,
- cite the commit it read,
- write records that your schema checks.
A typical agent turn has three calls. Search finds a starting record. A SPARQL query follows its links to the answer. The answer cites the rows and the commit.
The quickstart shows these steps in code. Your first search through MCP shows them as tool calls.
Run the server locally over stdio with npx @littlebigbrain/mcp. Or connect to
the hosted endpoint with OAuth sign-in. The server wraps the
@littlebigbrain/client SDK. This page describes version
0.16.0, which uses client 0.31.0.
Source and issues: github.com/littlebigbrains/lbb-mcp (Apache-2.0).
Discover the hosted MCP server
Section titled “Discover the hosted MCP server”The agent skills index provides focused instructions for connecting to MCP and querying a graph with its real vocabulary and commit evidence. It follows Agent Skills Discovery v0.2.0; each entry points to a Markdown skill and includes a SHA-256 digest. Verify the downloaded file against that digest before loading its instructions.
The AI catalog lists the
MCP server, both OpenAPI schemas and two agent skills, with stable identifiers
and example queries for semantic discovery. The same manifest is available at
the current ARD discovery path.
Follow its MCP server card to connect. The card describes
the hosted Streamable HTTP endpoint and requires your existing stack slug in
X-LBB-Stack. Follow the OAuth protected-resource metadata
for sign-in, then connect to https://mcp.littlebigbrain.com with that header.
You can also use the stack-specific URL described below.
The current SEP-2127 format
describes identity and connection details. The server reports capabilities and
the available tools when your MCP client connects. A
compatibility card
also provides the earlier serverInfo and capabilities fields for clients
that use the original well-known discovery path.
Browser tools on the marketing site
Section titled “Browser tools on the marketing site”The marketing site also exposes browser tools through WebMCP where the browser supports it. Agents can find and open public pages, read the current page and estimate Cloud or Pro pricing. The contact form lets an agent prepare an enquiry for the user to review and send. These browser tools operate on the marketing site; graph queries use the authenticated MCP server described here.
Discover the service documentation through DNS
Section titled “Discover the service documentation through DNS”Query the SVCB record at _index._agents.littlebigbrain.com to find the public
service documentation index. It advertises docs.littlebigbrain.com, HTTPS
on port 443 and the path /llms.txt through the experimental DNS-AID
well-known parameter, encoded as key65409 pending registration:
_index._agents.littlebigbrain.com. 3600 IN SVCB 1 docs.littlebigbrain.com. ( mandatory=alpn,port,key65409 alpn="h2,http/1.1" port=443 key65409="/llms.txt")Fetch the index to find the MCP, HTTP API and authentication documentation. A DNS-AID client needs to understand the mandatory path parameter to use this record. The hosted MCP connection still uses your stack’s URL and OAuth sign-in, as described below.
Task-shaped tools
Section titled “Task-shaped tools”The set has one tool per task. It does not mirror the HTTP routes.
| Tool | Purpose |
|---|---|
lbb_inspect |
graph context and exact reads: guide, graphs, paginated ontology/schema, publication status, conformance, metadata, entity, ontology change suggestions |
lbb_rdf |
import full RDF/OWL or add axioms using INSERT DATA (an update that removes asks the person to approve) |
lbb_query |
analytical reads: structured query, SPARQL text, search by meaning, questions in plain words, canned analysis, and four tools for writing queries (names, describe, commit_at, compare) |
lbb_embeddings |
search setup, read only: list and inspect embeddings, preview the text and cost of embedding a class |
lbb_embeddings_manage |
declare or refresh an embedding (spends model tokens) |
lbb_embeddings_delete |
delete an embedding and its vectors (asks the person to approve) |
lbb_fit_sources |
fit from text, read only: list the fit sources, preview the text the fit reads |
lbb_fit_sources_manage |
declare, dry-run or refresh a fit source (spends model tokens) |
lbb_fit_sources_delete |
delete a fit source (asks the person to approve) |
lbb_workflows |
starter workflows, read only: the starter workflows this server offers, the graph’s triggered workflows with their status, the preview of creating one, the workflows with triggers, what a watch has not sent yet, the history of a workflow’s settings, workflow tests, and what the runs did with each input |
lbb_workflows_manage |
create a workflow from a starter workflow on a class or change one, ask it to run now, pause and resume, define a workflow with triggers of your worker, use earlier settings of a workflow again, or start, answer and cancel a workflow test |
lbb_workflows_delete |
delete a triggered workflow or a workflow with triggers (asks the person to approve) |
lbb_reviews |
review items, read only: the questions for a person, one page at a time, one item, and the items grouped by pattern |
lbb_reviews_manage |
file a review item, answer one or a batch, comment, or withdraw an item (an answer that commits asks the person to approve) |
lbb_files |
files, read only: the graph’s files with their parse status, filtered by status or name, and the parsed lines of a page range, each with its box on the page |
lbb_commit |
preview/write statements or entity properties, and retract them (a retract asks the person to approve) |
lbb_model_choice |
the model each use runs, trials of other models with their reports, and the model choices of the workflow steps |
lbb_model_choice_manage |
start or stop a trial, switch a use to a tested model, revert (a trial spends model and judge tokens); set or remove the model of a workflow step |
lbb_models |
evaluation and training inputs, and the managed models’ activity |
lbb_evals |
label results as relevant or not, save evaluation queries, and check them at the current commit; read the model checks and correct one; keep datasets of examples |
lbb_evals_delete |
delete a dataset of examples (asks the person to approve) |
lbb_configure |
preview/define/evolve native metadata, list and apply ontology starters, suggest an ontology change, activate SHACL shapes, or keep the graph’s notes for questions in plain words (an evolve that removes and a reject-mode publish ask the person to approve) |
Call lbb_inspect with action: "ontology" before the agent writes a query or
a statement. The agent then uses only the types, relations and properties of
the pinned commit.
Read tools accept detail: "compact" | "standard" | "full". The default is
compact, which returns this envelope:
{summary, data, counts?, truncated?, rows_shown?, next?}.
Local (stdio): Claude Code, Cursor, Codex
Section titled “Local (stdio): Claude Code, Cursor, Codex”The client starts the server as a local process. They talk over standard input and output (stdio). This needs Node.js 18 or later.
Copy the complete endpoint and a stack API key from Connect in the
console. Add them to your client’s MCP
configuration, such as .mcp.json or mcp.json:
{ "mcpServers": { "lbb": { "command": "npx", "args": ["-y", "@littlebigbrain/mcp"], "env": { "LBB_BASE_URL": "https://<tenant-short-id>--<stack-slug>.db.eu.littlebigbrain.com", "LBB_API_KEY": "<your-stack-api-key>" } } }}| Variable | Meaning |
|---|---|
LBB_BASE_URL |
Required. The complete stack endpoint from Connect. Without it, the server starts and lists its tools, and each tool call fails with a message that asks for it. |
LBB_API_KEY |
The stack API key. Keep it in your local configuration. |
LBB_GRAPH |
Optional. The graph for calls that pass no graph. The default is main. |
LBB_MCP_DESTRUCTIVE |
Optional. allow runs a call that deletes or removes data without a question when the client cannot show one. Leave it unset to keep the question. See Approve destructive writes. |
Hosted (streamable-HTTP, OAuth)
Section titled “Hosted (streamable-HTTP, OAuth)”The hosted endpoint is https://mcp.littlebigbrain.com. It uses the MCP OAuth
sign-in. You sign in to your little big brain account. No stack API key is
stored on your machine. Claude-style clients use the URL of one stack:
{ "mcpServers": { "lbb": { "url": "https://mcp.littlebigbrain.com/mcp/<your-stack-slug>" } }}A client that supports remote MCP auth runs the sign-in by itself:
- It receives an authorization challenge from the endpoint.
- It opens the browser sign-in.
- It sends the resulting access token with each call.
The endpoint checks the token and confirms that your account owns the stack. It
then creates a short-lived session and runs the tools on that stack. Add
?graph=<name> to the URL to change the default graph from main.
| Response | Cause |
|---|---|
401 with an authorization challenge |
The access token is missing or not valid. The client signs in again. |
402 subscription_required |
The account’s subscription setup is not complete. Finish it in the console. |
403 insufficient_scope |
A claimed agent token lacks the trusted mcp:access permission. |
404 unknown stack |
Your account does not own a stack with that slug. |
405 |
The request was not a POST. |
503 |
The stack’s endpoint is not ready yet. Retry from the console. |
For agent identity registration, follow auth.md.
The guide uses WorkOS’s generated instructions once the issuer enables Agent
Registration, and the existing human OAuth flow until then. A claimed agent’s
access token must carry mcp:access, granting read and write access to its
organization’s stacks. Each request checks revocation, the completed
service-auth claim and the delegated user’s active membership before opening
a database session. See agent authentication.
You can also serve the tools over streamable HTTP with a stack API key. Run the HTTP server from your own Node process, as in Embed in a Node process.
Your first search and query through MCP
Section titled “Your first search and query through MCP”Run the quickstart first. It creates the support graph
with tickets, bugs, releases and a ticket embedding. Then connect one of the
transports above to the same stack. Ask your agent: which release fixed the
login bug?
The agent reads the schema first, with lbb_inspect:
{ "action": "ontology", "graph": "support" }It lists the types Ticket, Bug and Release and the links REPORTED_AS
and FIXED_IN. Next, the agent searches by meaning with lbb_query:
{ "mode": "search", "graph": "support", "text": "users cannot sign in after the upgrade", "top_k": 3}The top hit is the ticket login fails after 3.1. The agent takes its iri
and the response’s served_at_seq into the next call. It follows the links
with lbb_query at that commit:
{ "mode": "sparql", "graph": "support", "as_of_commit_seq": 1, "query": "PREFIX dr: <https://littlebigbrain.com/r/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?bug ?release WHERE { <iri-of-the-top-hit> dr:reported_as ?b . ?b rdfs:label ?bug ; dr:fixed_in ?r . ?r rdfs:label ?release . }"}The result has one row:
| bug | release |
|---|---|
| session token expiry | Release 3.2 |
The answer comes from two stored links. The agent does not infer the
connection from similar text. It can cite the rows and commit 1.
Replay an answer explains how long a commit stays
readable.
Build a graph through MCP
Section titled “Build a graph through MCP”An agent can also build a graph with tools alone. The calls below write the
quickstart records into a new graph, support-agent. The search and query
above then work on it with "graph": "support-agent".
Use a new graph for this. lbb_commit writes records by type and name, and
the quickstart writes them with a key. On one graph, that gives two records
for each ticket.
1. Preview the schema. Call lbb_configure. With dry_run: true, the
call shows the result and writes nothing:
{ "action": "define_ontology", "graph": "support-agent", "dry_run": true, "entity_types": ["Ticket", "Bug", "Release"], "relations": [ { "name": "REPORTED_AS", "source": "Ticket", "target": "Bug" }, { "name": "FIXED_IN", "source": "Bug", "target": "Release" } ]}Send the same call without dry_run to create the graph. A repeat of the same
call returns changed: false.
2. Add a field. Call lbb_configure again:
{ "action": "evolve_ontology", "graph": "support-agent", "ops": [{ "op": "add_property", "name": "description", "value_type": "text" }]}3. Write the records. Call lbb_commit with links (triplets) and field
values (entity_properties):
{ "graph": "support-agent", "triplets": [ { "source": { "type": "Ticket", "name": "login fails after 3.1" }, "relation": "REPORTED_AS", "target": { "type": "Bug", "name": "session token expiry" }, "evidence": "Support triage, 2 Sep" }, { "source": { "type": "Ticket", "name": "invoice PDF is blank" }, "relation": "REPORTED_AS", "target": { "type": "Bug", "name": "PDF fonts missing" }, "evidence": "Support triage, 3 Sep" }, { "source": { "type": "Ticket", "name": "CSV export times out" }, "relation": "REPORTED_AS", "target": { "type": "Bug", "name": "export runs on one thread" }, "evidence": "Support triage, 4 Sep" }, { "source": { "type": "Bug", "name": "session token expiry" }, "relation": "FIXED_IN", "target": { "type": "Release", "name": "Release 3.2" }, "evidence": "Release notes 3.2" }, { "source": { "type": "Bug", "name": "PDF fonts missing" }, "relation": "FIXED_IN", "target": { "type": "Release", "name": "Release 3.1.1" }, "evidence": "Release notes 3.1.1" } ], "entity_properties": [ { "type": "Ticket", "name": "login fails after 3.1", "properties": { "description": "Since 3.1, people are sent back to the login screen right after they type their password." } }, { "type": "Ticket", "name": "invoice PDF is blank", "properties": { "description": "Downloaded invoices open as empty pages." } }, { "type": "Ticket", "name": "CSV export times out", "properties": { "description": "Exports with more than 10,000 rows stop after 30 seconds." } } ]}The response reports commit_seq and echoes written_properties, the fields
that were stored.
4. Wait for publication. Call lbb_inspect until state is current:
{ "action": "publication", "graph": "support-agent" }5. Turn on search. Call lbb_embeddings_manage to declare an embedding on
the Ticket type:
{ "action": "declare", "graph": "support-agent", "class": "https://littlebigbrain.com/class/ticket", "from": ["label", "description"]}A declaration spends model tokens. Preview the text first with lbb_embeddings
and action: "preview". Then call lbb_embeddings with action: "get" and
name: "ticket" until the embedding reports serving.
Search by meaning covers each option.
Schema calls
Section titled “Schema calls”lbb_configure has these schema actions. Each one that writes takes
dry_run: true to preview without writing.
| Action | Arguments | Behavior |
|---|---|---|
define_ontology |
graph (required), entity_types and relations, or source with format; merge_default |
Creates the graph with its types and links. On an existing graph, it adds what is new. |
evolve_ontology |
ops (required, in order), graph |
Adds, renames, widens, narrows or removes types, links and fields. |
list_starters |
graph |
Lists the ontology starters (crm, documents, work) with each one’s status on the graph. |
apply_starter |
starter (required), expected_ontology_version, graph |
Adds what the graph lacks of a starter in one ontology version. Refused with starter_conflict when the graph holds a term differently. |
suggest_ontology_change |
title (required), change, facts, rationale, anchor, key, evidence, agent, graph |
Files the change as a suggestion for a person to review. change holds up to 128 evolve_ontology operations. facts holds graph facts (triplets, entity_properties, replace_owned, summary) that accepting commits; change may be empty when facts is set. Nothing changes until a person accepts it. |
publish_schema |
shapes (required), desired_mode, confirm_restrictive, ontology, graph |
Activates SHACL rules. In reject mode it asks the person to approve first. See Validate writes. |
get_rewrite_profile |
graph |
Reads the graph’s profile: the notes and worked examples the model reads for every question in plain words, and its version. |
set_rewrite_profile |
notes, examples (up to 20 {question, sparql, note?}), expected_version, graph |
Stores the profile. Pass the version you read as expected_version; another write first answers 409 conflict. |
For define_ontology, give both entity_types and relations. Each type is a
name or { "name": … }. A type object accepts name, description,
resolvable and super_types. Another field fails with HTTP 400, which lists
the accepted fields.
A link object has name, source and target, as in the example. It also
accepts description, inverse, symmetric, transitive, reducer,
cardinality and temporal_semantics.
merge_default: true adds the built-in AI-context vocabulary under your types.
The tool’s default is false.
On an existing graph, define_ontology refuses a change that narrows a link’s
source or target types. The error is ontology_restrictive_change. Use
evolve_ontology with narrow_relation for that change.
super_types and add_super_types store each parent as an rdfs:subClassOf
statement. A query with entailment: "subclass" then matches the records of
each subtype. See Reasoning.
define_ontology also takes a source document instead of names. Its format
is auto (the default), turtle, json_ld, rdf_xml, csv, tsv,
lbb_json or spec. lbb_json expects a serialized ontology. spec is the
JSON form above.
From an RDF or OWL document, define_ontology keeps only types and links. To
store the whole document as queryable facts, use lbb_rdf.
evolve_ontology takes these op values:
op |
Arguments |
|---|---|
add_entity_type |
name |
add_super_types |
entity_type, super_types |
add_relation |
name, domain, range, cardinality, temporal_semantics, reducer, inverse_name, transitive, symmetric |
add_property |
name, value_type (bool, i64, f64, date_time, keyword, text or bytes; default text), required, unit (of an i64 or f64 field, such as mm, kg or h), allowed_values |
set_property_unit |
property, unit (leave it out to clear the unit) |
set_property_constraint |
property, allowed_values (an empty list clears the constraint) |
widen_relation |
relation, add_domain, add_range |
narrow_relation |
relation, remove_domain, remove_range |
rename_entity_type, rename_relation |
from, to |
set_relation_inverse |
relation, inverse_name |
set_relation_cardinality |
relation, cardinality |
remove_entity_type, remove_relation |
name |
allowed_values is enforced: a commit with another value for the field
fails. It works on keyword, text, i64 and bool fields. Values stored
before a constraint or a unit change stay as they are: a unit change converts
nothing, and a constraint checks only later commits.
A removed type or link stays readable in old records. New commits that use it
fail. Preview a narrowing or removing change with dry_run: true. The preview
reports conflicts with current data. Repair them, then apply.
allow_data_conflicts does not skip that check. A call that removes asks the
person to approve first. See
Approve destructive writes.
Write calls
Section titled “Write calls”lbb_commit has three modes. It picks retract when you pass
retract_edges or retract_entities, and search_feedback when you pass
search_feedback. Otherwise it writes facts.
| Argument | Meaning |
|---|---|
triplets |
Links. Each has source and target as { "type", "name" }, a relation, and optional evidence, confidence (0 to 1) and valid_time (start, end, granularity, source_text). |
entity_properties |
Field values. Each item is { "type", "name", "properties" }. |
entity_embeddings |
Vectors you computed yourself. Each item has type, name, optional key or entity_id, model_id, vector, and optional metric. |
dry_run |
Checks a facts commit, returns its SHACL report, and writes nothing. |
observed_at |
An RFC 3339 time. The commit is recorded as of that time, for backfills. |
edge_idempotency |
append (the MCP default) or skip_unchanged. |
idempotency_key |
Optional. See Idempotent writes. |
retract_edges |
Links to remove, each { source, relation, target }. |
retract_entities |
Records whose current links are all removed. Their history stays readable. |
search_feedback |
Relevance labels for search results. |
Values are converted to each field’s declared type. The string "52" lands in
an i64 field, and "2026-06-26" in a date_time field. An undeclared field
fails the commit with HTTP 400. Declare the field with add_property first.
The source and target of a triplet carry only type and name. The tool
drops a key there. entity_properties items pass a key through.
retract_edges and retract_entities also match records by type and name. A
record written with a key does not match, and the call returns no_op: true.
A retract asks the person to approve first. See
Approve destructive writes.
A graph whose first write is RDF refuses lbb_commit with HTTP 400
rdf_native_graph. See Add RDF and OWL.
For search_feedback, send the query, an optional search_id, and
labels. Each label has a target, a grade, and optional rank, score,
reason and split. Grades are 3 (good), 1 (partly relevant) and 0
(bad).
A target is { "kind": "entity", "entity": { "entity_type", "name" } }. The kinds
assertion, observation and concept name other targets.
Query options
Section titled “Query options”lbb_query has nine modes. Each read answers from one commit.
SPARQL text
Section titled “SPARQL text”mode: "sparql" runs SPARQL 1.1 SELECT and ASK queries. CONSTRUCT and
DESCRIBE return HTTP 400. Use the /sparql endpoint for
them.
| Argument | Meaning |
|---|---|
query |
The query text. Required unless cursor is set. |
entailment |
none (default), subclass, rdfs or owl. See Reasoning. |
consistency |
eventual reads the latest published commit. strong also applies the newest writes. |
min_indexed_seq |
Read at this commit or a later one. |
as_of_commit_seq |
Read the graph as it was at this commit. |
row_limit |
Rows per page. See Pages and large results. |
cursor |
The next.cursor of the previous page. |
request |
The user’s words behind the query. The server records an eval trace, and the result names its trace_id. |
detail, graph |
As for every tool. |
Without as_of_commit_seq, the tool reads the graph’s latest commit number
first. Every page of that query then reads that commit.
A valid-time as_of is refused before any HTTP call, also inside an older
cursor. Use as_of_commit_seq for an earlier commit.
A SPARQL query can also search by meaning. The pattern
?x <https://littlebigbrain.com/search#similarTo> "words" binds the records
nearest to the words, and the other patterns of the query filter and join
them. The result then carries search: the plan (nearest, filter_first
or search_first), the hits asked for and bound, and complete. When
complete is false, notes says so. With search:rerank true and
search:relevance ?r, the rerank model keeps the hits that answer the words
and binds its answer; search.rerank reports how it went.
Search inside a SPARQL query
lists the patterns.
Structured JSON
Section titled “Structured JSON”mode: "structured" takes a JSON body instead of query text. A predicate
is a link name, in any case. This body counts the tickets fixed in each release:
{ "mode": "structured", "graph": "support", "body": { "patterns": [ { "subject": { "var": "t" }, "predicate": "REPORTED_AS", "object": { "var": "b" } }, { "subject": { "var": "b" }, "predicate": "FIXED_IN", "object": { "var": "r" } } ], "group_by": ["r"], "aggregates": [{ "func": "count", "as": "tickets" }] }}Each release comes back in groups, with its record under keys.r and the
count under aggregates.tickets.
| Body field | Shape |
|---|---|
patterns |
[{ subject, predicate, object }]. A term is { "var": "x" } or a fixed { "entity": { "entity_type", "name" } }. |
filters |
{ "compare": { "op", "left", "right" } }, or and, or, not of filters. op is eq, ne, lt, le, gt or ge. |
| Filter operand | { "var" }, { "property": { "var", "field" } }, or { "value": … } with one of str, i64, f64, bool, date_time, entity. |
group_by |
Variables to group by record. |
group_keys |
{ "property": { var, field, as } }, or { "date_bucket": { var, field, granularity, as } } with year, month, week, day or hour. Values come back under value_keys. |
aggregates |
{ func, as } with count, sum, avg, min or max, and optional operand and distinct. |
having |
Filters over the groups. |
order_by |
[{ var, descending }] |
select, distinct, as_of_commit_seq |
Projection, duplicate removal, and a commit pin. |
To count groups without reading them, add an equality having and set
row_limit: 1. Then read row_page.total. A body with combinators fails:
write OPTIONAL, UNION, MINUS or EXISTS as SPARQL text.
Search by meaning
Section titled “Search by meaning”mode: "search" takes text. It searches every searchable type, or one
embedding. Other arguments are top_k (at most 200), probe,
include: ["text"], filter, explain and request.
A filter item names a class or a link. A class item is { "class": … }. A
link item is { "via": …, "to": … }. Its direction is out (the default) or
in.
With explain: true, the call returns the plan without calling the model.
Search by meaning explains filters and planning.
Questions in plain words
Section titled “Questions in plain words”mode: "question" takes a question in plain words and calls
POST /v1/query/ask. The server describes the graph and picks the kind of
question. Its model runs queries in a short loop, reads the rows, and
answers. The result has the answer with the records it cites, the steps, the
route, the query whose rows hold the answer, the rows and the eval
trace_id. It takes about 6 to 12 seconds.
| Argument | Meaning |
|---|---|
question |
The question, 1 to 4,000 characters. Required. |
context |
Notes on what the data means: units, names to prefer. Send the same text with each question. |
route |
Fixes the kind of question: lookup, aggregate, search, history, schema or unanswerable. |
limit |
The rows each query returns, 1 to 1,000. |
anchor |
The IRIs of records the question is about, at most 10. The queries use them directly. |
timeline |
Dates that stand for the graph’s commits, at most 200: [{date, as_of_commit_seq, label?}]. A question about a date reads the commit of the latest point on or before it. |
detail, graph |
As for every tool. |
The result lists in linked the names of the question that the server found
in the graph, and in anchors what it read about each IRI of anchor. A
history question returns history: the commit the server read for its date,
and for an answer from a comparison the rows added, removed and
changed with totals. Each list shows at most 20, 100 or 500 entries by
detail; history.shown and a note say when a list is cut. The rows are
those of the query the answer stands on. The answer and run arguments of
earlier versions are gone: the mode always answers.
When the client asks for progress (a progressToken in the call’s
_meta), the tool sends each step as a progress notification: the route,
each tool call of the loop, and the answer. The result stays the same.
Cancelling the call stops the server’s work.
Use this mode when the agent has not read the schema. When it has, a query
it writes itself in mode: "sparql" needs no model call. An unanswerable
route means the graph does not hold the data.
Answer questions in plain words covers the
routes and the limits. It also lists the data that goes to the model
providers.
Tools for writing queries
Section titled “Tools for writing queries”Four modes give an agent that writes its own SPARQL what only the server knows. None calls a model.
| Mode | Arguments | Use it when |
|---|---|---|
names |
text, limit (1 to 10) |
The question names a record. The result groups the candidates by name, the one to prefer first; put its IRI in the query. |
describe |
question, or classes and properties as IRIs |
The agent needs classes or properties it has not seen. The result is the server’s text: how many sampled instances hold each property, and the values of small classes. detail: "full" adds the JSON. |
commit_at |
date (YYYY-MM-DD) or moment (RFC 3339) |
The question names a date. Run the query with mode: "sparql" and the commit it returns as as_of_commit_seq. |
compare |
query, before, after, key, max_rows, limit |
The question asks what changed. before and after are each {as_of_commit_seq}, {date} or {moment}. The result has added, removed and changed as lexical rows, with totals; pass next back for the next page. |
Summary charts
Section titled “Summary charts”mode: "analyze" returns counts with a Vega-Lite chart. Set metric to
entity_types, relations, overview, or sparql with a structured body in
sparql. chart is bar (default) or pie, and top_k keeps the largest
values.
Pages and large results
Section titled “Pages and large results”A query page holds at most row_limit rows. The default depends on detail:
20 for compact, 100 for standard, 1,000 for full. The maximum is 5,000.
Each page reports
row_page: {returned, total, offset, limit, has_more, next_offset?}. Its
summary says returned X of Y rows. When more rows exist, next holds the
arguments for the next page:
{ "mode": "sparql", "cursor": "eyJhc19vZl9jb21taXRfc2Vx…", "row_limit": 2, "detail": "compact" }Pass next back to lbb_query until it is absent. You do not write LIMIT
and OFFSET. The cursor holds the query, the graph and the commit of page 1.
New writes between pages do not change the rows of later pages.
A cursor must match the arguments sent with it. A different query, graph,
row_limit, entailment, consistency or min_indexed_seq fails.
A page keeps whole values within 80,000 bytes of UTF-8. So a page can be
shorter than row_limit. Follow next even then. A cursor moves on only by
the rows you received.
If one row alone is too large, project fewer fields. Or read that row through the SPARQL HTTP endpoint.
Other read tools shorten large values by detail. compact keeps 5 items per
list and 300 characters per string. standard keeps 20 and 1,000. full keeps
100 and 5,000. A shortened result sets truncated and names the next detail
level in next.
A list page (data with has_more and next_cursor) asks the server for at
most the items its detail level keeps, so detail never shortens the page.
A page over 80,000 characters is asked for again with fewer items. Its
next_cursor then continues after the last item shown. next_cursor is
never shortened.
Read the schema and records
Section titled “Read the schema and records”lbb_inspect reads graph context and exact records:
| Action | Returns |
|---|---|
guide |
Counts, types, links and suggested next calls. For a missing graph, the list of graphs and how to create one. |
graphs |
The graphs of the stack. Works before any graph exists. |
publication |
Whether writes are published: state, head_seq, published_seq, lag_commits. |
ontology |
Types, links and fields, with counts, in complete pages. |
schema |
The active schema and SHACL metadata, in complete pages. It runs no validation. |
ontology_conformance |
The published SHACL report: conforms, result_count, validated_at_seq. |
ontology_search |
Types, terms and links that match query, up to top_k. |
metadata |
Graph status, including the latest commit. |
entity |
One record by entity_id, or by entity_type and name: its fields and its links. Accepts as_of_commit_seq. A valid-time as_of is refused before any HTTP call. |
ontology_suggestions |
The ontology change suggestions and their state, with identity_count and fact_count (the links and field rows accepting commits). status keeps one state: open, accepted, dismissed or superseded. limit is 50 by default. |
ontology and schema return complete entries. page_size sets entries per
page: 50 by default, at most 500. section limits the pages to one list, such
as entity_type_defs, relation_defs, property_defs, classes or
relations.
Pass the returned next arguments until they are absent. Nested values are
never shortened, also with detail: "compact".
A single entry can exceed the output budget. The result then carries
entry_fragment. Join its serialized_json parts in char_offset order, then
parse the JSON.
A schema change between pages fails the cursor, so pages never mix versions.
Start again without cursor after a change.
Add RDF and OWL
Section titled “Add RDF and OWL”lbb_rdf stores RDF statements as graph facts. It has two actions:
| Action | Arguments | Behavior |
|---|---|---|
import |
source (required), format (turtle default, ntriples, nquads, trig), base_iri, blank_node_scope, idempotency_key, graph |
Stores a complete document: lists, labels, comments and OWL statements. |
update |
update (required), idempotency_key, graph |
Runs SPARQL Update INSERT DATA. |
import accepts the default RDF graph only. An N-Quads or TriG document must
contain only default-graph statements.
update accepts only INSERT DATA. DELETE, WHERE, CLEAR and the other
forms return HTTP 400 and change nothing. Named graphs are refused too.
A graph whose first write is RDF is RDF-native. It refuses later
lbb_commit writes with rdf_native_graph. Decide the write path before the
first write. A graph first written with lbb_commit accepts lbb_rdf as well.
This call adds a type hierarchy to the support graph. It states that every
bug is an issue:
{ "action": "update", "graph": "support", "update": "INSERT DATA { <https://littlebigbrain.com/class/bug> <http://www.w3.org/2000/01/rdf-schema#subClassOf> <https://example.org/support/Issue> }"}The response has accepted: true, which means the statement is stored.
Queries use it once its commit is published.
Wait for publication with lbb_inspect action: "publication". Then check the
answer with entailment:
{ "mode": "sparql", "graph": "support", "entailment": "subclass", "query": "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?issue WHERE { ?b a <https://example.org/support/Issue> ; rdfs:label ?issue } ORDER BY ?issue"}The query returns the three bugs. Without entailment, it returns no rows.
Reasoning & inference lists the
OWL statements that entailment: "owl" applies.
To read the stored statements, query with entailment: "none" and follow each
next cursor:
SELECT ?s ?p ?o WHERE { ?s ?p ?o} ORDER BY ?s ?p ?oRDF statements cannot be removed or replaced. An import of a changed document adds its new statements and keeps the old ones.
To revise a document, import it into a new graph and check it. Then move your clients to that graph. Keep the original graph until you choose to delete it.
A retry with the same content writes nothing new. To write the same content
again on purpose, pass a new idempotency_key.
Validate writes with SHACL
Section titled “Validate writes with SHACL”SHACL is the W3C standard for validation rules. lbb_configure with
action: "publish_schema" activates a set of rules:
{ "action": "publish_schema", "graph": "support", "dry_run": true, "desired_mode": "warn", "shapes": { "format": "turtle", "source": "@prefix sh: <http://www.w3.org/ns/shacl#> . @prefix dclass: <https://littlebigbrain.com/class/> . @prefix dr: <https://littlebigbrain.com/r/> . <https://example.org/shapes/Ticket> a sh:NodeShape ; sh:targetClass dclass:ticket ; sh:property [ sh:path dr:reported_as ; sh:maxCount 1 ; sh:message \"A ticket is reported as at most one bug.\" ] ." }}shapes.formatisauto,turtle,n_triples,n_quadsortrig.desired_modeisoff,warnorreject.confirm_restrictiveis accepted. The server does not read it.ontologymust match the current schema. Change the schema withdefine_ontologyorevolve_ontology.
The preview parses the rules and checks them against the schema. It writes nothing and starts no validation job. It does not check your data.
Tighten rules in this order:
- Publish in
warnmode. - Read the report with
lbb_inspectaction: "ontology_conformance". - Repair the records it lists.
- Publish the same rules in
rejectmode.
In reject mode, a write that breaks a rule fails, and the error lists the
violations. A publish in reject mode asks the person to approve first, with
the target classes of the rules. See
Approve destructive writes. lbb_commit with dry_run: true returns the same report without
writing. See Query and validate.
Errors
Section titled “Errors”A failed call sets isError. Its structuredContent.error keeps every field
of the server error:
{ "error": { "type": "not_found_error", "code": "graph_not_found", "message": "graph 'nope' does not exist for this tenant", "param": "graph", "request_id": "8661a030-…", "doc_url": "https://docs.littlebigbrain.com/sdks/errors/#graph_not_found", "status": 404 }}An error the tool finds before any HTTP call has type and code
tool_error. Examples are an unknown argument and a cursor that does not match
its query.
A graph error can name only a storage key. The tool then rewrites the message.
The new message lists the stack’s graphs and the graph value to pass.
Idempotent writes
Section titled “Idempotent writes”Without an idempotency_key, lbb_commit and lbb_rdf derive one from the
graph and the content. A retry with the same content writes nothing new.
lbb_commit then returns the first result with idempotent_replay: true.
To repeat an identical write on purpose, pass a new idempotency_key.
lbb_commit sets edge_idempotency to append by default. New evidence on an
existing link is then recorded. Pass skip_unchanged for backfills that you
run again. It skips exact copies of current links, and repeats that differ only
in evidence.
Approve destructive writes
Section titled “Approve destructive writes”A call that deletes or removes data asks the person first. The server sends
the question through the client with MCP form elicitation. The question
names what the call removes first, with the counts, for example
Delete the embedding "ticket" of graph "support" and its vectors?. It has
one confirm box.
- When the person approves, the call runs.
- When the person declines or cancels, nothing is sent. The tool returns an
error with the code
approval_declined. - When the approval request fails, nothing is sent either. The code is
approval_failed.
These calls ask:
| Call | What the question names |
|---|---|
lbb_embeddings_delete |
the embedding and its graph |
lbb_fit_sources_delete |
the fit source and its graph |
lbb_workflows_delete |
the workflow, its starter workflow and its graph |
lbb_evals_delete |
the dataset, its id, its item count and its graph |
lbb_commit with mode: "retract" |
the counts, then each link and record it removes (the first 20 of each, then a count) |
lbb_rdf with an update that holds DELETE, CLEAR, DROP, MOVE or COPY |
each operation that removes, quoted on lines of its own, then the forms of the other operations |
lbb_configure with action: "evolve_ontology" and remove_entity_type, remove_relation, or narrow_relation with remove_domain or remove_range |
the counts, then each type and link it removes and each type it takes out of a link’s source or target types (the first 20, then a count) |
lbb_configure with action: "publish_schema" and desired_mode: "reject" |
the target classes of the rules and the size of the source |
lbb_reviews_manage answer or answer_batch that accepts or corrects a value item, or accepts a change item |
the count and the effect: how many items commit a value and how many apply an ontology change, then each item with its value, or with what its change removes |
The question escapes newlines and other control characters in names and values, so a name cannot add lines of its own.
lbb_model_choice_manage put_choice and delete_choice ask nothing. They
change only the model of a workflow step’s future calls, remove no data,
and a choice is set again in one step.
Some calls read first, so the question can name what they change.
lbb_evals_delete reads the dataset. When it does not exist, that read fails
with 404, and nobody is asked. A review answer reads its items, and the
suggestion of each change item. An answer that commits nothing asks
nothing: a reject, a cant_tell or a choose, and an answer to an item
that is answered, withdrawn or in test scope. The answer to an item that
Evals filed (a check, a calibration question, a golden) is a grade or a
choice, so it asks nothing either. A preview (dry_run: true)
of an evolve_ontology or a publish_schema writes nothing, so it does not
ask.
Some clients cannot show the question: a client without elicitation, or
with URL elicitation only. The HTTP transport of this server, which the
hosted endpoint uses, handles each call as a request of its own, so it
cannot ask either. Then the call fails with approval_required, and nothing
is sent. No tool argument changes that, since the agent sets the arguments.
The person who runs the MCP server can set LBB_MCP_DESTRUCTIVE=allow in
its environment. The server then runs these calls without a question when
the client cannot show one.
The hosted endpoint does not set it. There, every call that deletes or
removes data answers approval_required. Make that change in the console
or with the TypeScript or Python SDK instead.
The server writes one JSON line per tool call to standard error:
{"event":"mcp_tool_call","tool":"lbb_embeddings_delete","outcome":"error","code":"approval_declined","approval":"declined","request_id":7}action names the call’s action, approval what the approval step decided
(approved, declined, cancelled, failed, unavailable or
allowed_by_setting), and request_id the JSON-RPC request. A line holds no
arguments, names or texts.
Other tools
Section titled “Other tools”| Tool | Actions |
|---|---|
lbb_embeddings |
list: each embedding’s status, progress and lag, and the graph’s model. get: one embedding by name. preview: the text of sample records and the facts of a class, with no model call. |
lbb_embeddings_manage |
declare: a new embedding or a changed recipe (class, from, exclude, title, name). refresh: one embed step now, by name. model: move every embedding of the graph to model (and dim). |
lbb_embeddings_delete |
Deletes the embedding name and its vectors, once the person approves. |
lbb_fit_sources |
list: each fit source’s status, the suggestions it filed and this month’s spend. get: one by name. preview: the text the fit reads for a few records of a class, with no model call. |
lbb_fit_sources_manage |
declare: a fit source on a class (class, from, exclude, context, name); the server reads every record and files ontology suggestions. dry_run: the proposals for up to 3 records, nothing filed (spends model tokens). refresh: ask the job to run now, by name (returns at once). |
lbb_fit_sources_delete |
Deletes the fit source name, once the person approves; its suggestions stay. |
lbb_workflows |
starters: the starter workflows this server offers, with their group, their settings and whether each can run here. list: the graph’s triggered workflows with their state, lag, counters, spend and last error. get: one, by starter and name, with its own status in details. preview: what creating a workflow would do for starter, class, fields, exclude and params (and workflow, owns and batch for a developer workflow, whose preview shows its first trigger messages): the resolved watch, the instance count and the starter workflow’s own preview. It writes nothing. workflows: the workflows with triggers, or one by name, with each one’s target type, shards, routing field, window, trigger and shard inboxes. queue: what a workflow’s watch has not sent yet, by name, each record with its shard and origin, one page in data (cursor takes the answer’s next_cursor; limit, trigger). run_results: what a workflow’s runs did with each input, by name, newest run first: the input, its outcome and its values with their quotes and review items, one page in data (run for one run with run_counts, outcome, iri, cursor, limit). revisions: the history of a workflow’s settings by name, newest change first (cursor, limit 1 to 100): each item a revision (its settings, its id wrev_…, the hash of those settings) with who changed it, when, how, and bound (the one in use). revision: one revision by name and revision; compare two by their settings. tests: one page of the graph’s workflow tests, newest first (name, limit, cursor). tests_get: one test by id, with each input’s text and, per value, its quote, its support and what the live workflow does with it. |
lbb_workflows_manage |
use: create a workflow from a starter workflow on a class, or change one (starter, class, fields, exclude, params, name, gate, budget_usd_per_month); the workflow reads every instance, then follows each published commit. A developer workflow (starter: "workflow") also takes workflow (workflow_type, version), owns (classes, relations, properties) and batch (1 to 64). refresh: ask the workflow to run now, by starter and name (returns at once). pause and resume: stop a workflow from reading and sending, or let it catch up. Every workflow pauses but search.embed and ontology.fit, which answer workflow_pause_unsupported. Without starter they name a workflow with triggers. define: create or change a workflow with triggers of your worker (name, workflow, one trigger, owns, batch, shards, route_by, window, trigger). The trigger is class and fields (a watch), media_types (a content trigger on uploads), schedule ({cron, timezone} or {every, offset}, and jitter) or stream ({max_wait}: the events a client sends, in batches). run: run one now, by name. activate: make a kept revision the one in use, by name and revision, with expected_revision (the revision you read as bound) so a change by someone else since fails with workflow_revision_conflict. An activation changes what the workflow does from then on and deletes no data, so it is not a destructive write and asks for no confirmation. Show the user what changes first. tests_create: test a values.extract workflow on chosen inputs before it writes. Name a workflow of the graph (name), or pass install, the use request of a workflow you have not created. Add iris (at most 20) or sample (1 to 20, default 6). tests_answer: the person’s answer to one value (id, iri, property, answer); answer: null removes it. tests_cancel: stop a test by id. A test writes nothing to the graph. |
lbb_workflows_delete |
Deletes the triggered workflow of starter named name, or without starter the workflow with triggers named name, once the person approves; what it wrote stays. |
lbb_reviews |
list: one page of review items, the latest update first, as the server sends it (object, data, has_more, next_cursor). Filters: status, kind (one or a list), scope, origin_id, workflow, run, key, eval_id (the items Evals filed for one record: a calibration session, a model call’s check, a golden); page with limit and cursor. get: one item by id. patterns: the live items grouped by the decision they ask (status, origin_id, type, eval_id). |
lbb_reviews_manage |
create: file an item of kind value, choice, grade or answer (kind, title, question, and subject, evidence, rationale, key, scope, facts, origin). answer: answer one item (id, answer, revision). answer_batch: one answer for up to 500 ids. comment (id, text, author). withdraw (id, reason). |
lbb_files |
list: 50 files a call, newest upload first, with their SHA-256, name, size, Document IRI and parse status; when more follow, next names the after of the next call. parse_status keeps the files of one status: parsed, waiting, unsupported or failed. name keeps the files whose name holds a text, in any case. A filtered list reads the published generation and returns its commit (as_of_commit_seq). A new upload can be missing from it until publication. Its next repeats the filters. pages: the parsed pages of one file, by sha256 or by its exact name (a file of any age), from from to to (0-based, to excluded, one page by default). Each line comes as <line id> [x0,y0,x1,y1] <text>, the box normalized to the page. contains keeps the lines that hold a text, max_lines caps the lines (200 by default, at most 1,000), and next names the from and line_offset of the next call. |
lbb_evals |
summary, traces, trace, label, judge, goldens, golden, accept, delete, run, results, settings. Model checks: checks_summary, checks, review_check. Datasets: datasets, datasets_get, datasets_export, datasets_create, datasets_items. |
lbb_evals_delete |
Deletes the dataset id with its items, once the person approves. A later datasets_get or datasets_export of it fails with 404, and the next save of its workflow test makes a new dataset. |
lbb_model_choice |
options: per use (ask, route, rerank, fit, label) the model it runs now, LBB’s model, a switch, its checked calls and the models a trial can test. trials (job, limit): the trials with their reports. trial (trial_id): one trial with its compared calls. trial_call (trial_id, call_id): both answers and the ground truth. switches: the switched uses. choices (workflow, use, cursor, limit): the model choices of the workflow steps (extract, decide, embed): the environment’s rows, and with workflow the row in force for each step of that workflow; one page in data, with has_more and next_cursor. |
lbb_model_choice_manage |
start: test a candidate (provider, model, effort) on the uses in jobs, with an optional target and days; it changes no model. stop (trial_id). switch (trial_id): the use runs the candidate from the next call on; only a trial that qualifies and compared with the model in use. revert (job): back to LBB’s model. Agents show the report and switch only what the user confirmed. put_choice (use, provider, model, effort, workflow): the step runs that model from its next call, for the environment or one workflow. delete_choice (use, workflow): the step runs the next level again; it answers {id, object, deleted: true}. |
lbb_models |
shadow_eval (with a body), suggest_dataset, extractor_dataset (with limit, split_seq). activity: one month of the stack’s managed-model use, by feature, day and graph (month as yyyy-mm; the current month by default). |
With lbb_evals, an agent records what the user confirmed about an answer:
- Run a query or search with
request, the user’s words. The result names atrace_id. - For a question, label the whole answer with
action: "label",trace_idandvalid:truewhen the query is right for the question. Withvalid: false,sparqlgives the right query. - For the results, read their ids with
action: "trace"and label them withitemandvalid, oritems. A search by meaning needs these labels: no query says which hits are right.
golden saves a query and treats its current results as relevant. run
checks every golden at the current commit: a question is asked again through
Ask (POST /v1/query/ask, its answer loop), and a saved query or search runs
again. The verdict of a question shows the loop’s final query and its answer
with the records it cites. judge lets the platform’s
judge model label unlabeled results.
lbb_evals also reads the model checks. A
judge model checks a sample of the model calls LBB makes for the graph:
checks_summarysums a month per job and model, with the judge’s agreement with people.monthisyyyy-mm; the default is the current month.checkslists the month’s checks, newest first. Each has the judge’s verdict, score and reason, and the ground truth.job,verdictandreviewedfilter the list, andafterreads the next page.review_checkrecords a review of one check by itscall_id.agree: truekeeps the judge’s verdict.agree: falsewithverdictcorrects it, with an optionalscore,referenceandnote.
A review becomes the call’s ground truth. Show the check to the user first, and review only what the user confirmed:
lbb_evals action=checks verdict=wrong reviewed=falselbb_evals action=review_check call_id=<call> agree=false verdict=right note="The user confirmed the order."Review items
Section titled “Review items”A review item is a question for a person. Workflows, integrations, agents and people file them, and the console’s Review inbox shows them. Each kind takes its own decisions:
| Kind | Asks | Decisions |
|---|---|---|
change |
accept an ontology change, identities or facts | accept, reject, cant_tell |
value |
confirm one value of a property | accept, correct (with value), reject, cant_tell |
choice |
pick one of question.options |
choose (with option), cant_tell |
grade |
grade question.output on the scale question.options |
choose (with option), cant_tell |
answer |
answer question.prompt in words |
accept (the text in note), cant_tell |
An accepted or corrected value item commits the value to the graph. Show
the item to the user, and answer only what the user decided:
lbb_reviews action=list status=open kind=valuelbb_reviews action=get id=rev_…lbb_reviews_manage action=answer id=rev_… answer={"decision": "correct", "value": 45} revision=3An answer that accepts or corrects a value item, or accepts a change
item, commits facts or applies an ontology change. It asks the person to
approve first. See Approve destructive writes.
An item has one answer. The same answer again returns the item. Another
answer fails with 409 review_answered. revision is the revision the
person saw; a later one fails with 409 review_stale.
A list page holds at most the items the detail level shows: 5 (compact),
20 (standard) or 100 (full). The page then comes back whole, and
next_cursor continues after the last item you read. Each write sends an
idempotency key. A retry after a network failure or a 5xx sends the same
key, so the write happens once.
Ask a person shows how workflows file items
and use the answers.
Workflow tests and datasets
Section titled “Workflow tests and datasets”A workflow test runs a values.extract workflow
on a few inputs and writes nothing to the graph. The answers to its values
become a dataset of examples:
lbb_workflows_manage action=tests_create name=sinks sample=6lbb_workflows action=tests_get id=wtest_…lbb_workflows_manage action=tests_answer id=wtest_… iri=<input> property=width_cm answer={"decision": "correct", "value": 45}lbb_evals action=datasets_create name=sinks source={"kind": "test", "id": "wtest_…"}lbb_evals action=datasets_export id=ds_…datasets_create also takes the examples themselves: name, items,
install (each property’s value type, the units, the context) and about.
Each item has a name, its text, the values a correct run writes and
the ones it must leave_out. datasets_items adds items to a dataset; an
item with the name of one it holds replaces it. lbb_evals_delete deletes
a dataset by id, once the person approves. A dataset ends with its graph.
Storage inspection and other operator actions are not in the tool set. Publication and cleanup run automatically.
Embed in a Node process
Section titled “Embed in a Node process”The package exports three functions:
| Export | What it does |
|---|---|
createMcpHttpServer(options) |
Returns a Node http.Server that serves the tools over streamable HTTP. Each caller sends a stack API key as a bearer token. |
buildLbbServer(client, options?) |
Returns an MCP server bound to one LbbClient. |
registerLbbTools(server, client, options?) |
Adds the tools to an MCP server you already have. |
This process serves the tools on http://127.0.0.1:8080/mcp:
import { createMcpHttpServer } from "@littlebigbrain/mcp";
const server = createMcpHttpServer({ baseUrl: process.env.LBB_URL!, mcpPath: "/mcp", allowedHosts: ["127.0.0.1", "localhost"], onError: (error) => console.error("MCP request failed", error),});server.listen(8080, "127.0.0.1");A client sends POST /mcp with a JSON body and Authorization: Bearer <stack API key>. Add ?graph= to change the default graph. GET /healthz
needs no key.
| Option | Default | Meaning |
|---|---|---|
baseUrl |
Required | The complete stack endpoint. |
mcpPath |
/mcp |
The path that serves MCP. |
maxBodyBytes |
1,048,576 | Larger bodies get 413. |
requestTimeoutMs |
30,000 | The request timeout, in milliseconds. |
allowedHosts |
None | Host names that the Host header must match. A present Origin must match too. Others get 403. Set it when the server is reachable from a browser. |
allowedOrigins |
None | Extra exact Origin values to accept. |
onError |
None | Called with each failed request’s error. |
clientFactory |
new LbbClient(…) |
Builds the LbbClient for each request from baseUrl, apiKey and graph. |
| Response | Cause |
|---|---|
401 |
No bearer token. |
415 |
The Content-Type is not application/json. |
400 |
The body is not valid JSON. |
413 |
The body is larger than maxBodyBytes. |
403 |
The Host or Origin is not allowed. |
404 |
Another path, or a method other than POST on mcpPath. |
500 |
An unexpected error. The body is internal server error, and onError receives the details. |
This server has no OAuth. Put your own authentication in front of it before you expose it to a network. The hosted OAuth endpoint is a separate service.
To add the tools to your own MCP server, next to your own tools:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";import { LbbClient } from "@littlebigbrain/client";import { registerLbbTools } from "@littlebigbrain/mcp";
const lbb = new LbbClient({ baseUrl: process.env.LBB_URL!, apiKey: process.env.LBB_API_KEY!, graph: "support",});
const server = new McpServer({ name: "support-agent", version: "1.0.0" });registerLbbTools(server, lbb);await server.connect(new StdioServerTransport());buildLbbServer(lbb) does the same with a new server named lbb. Both accept
these options:
| Option | Default | Meaning |
|---|---|---|
queryTextFormat |
compact |
compact or pretty: the format of query results. |
destructiveWithoutApproval |
allow when LBB_MCP_DESTRUCTIVE=allow, else refuse |
What a call that deletes or removes data does when the client cannot ask the person. See Approve destructive writes. |
log |
A JSON line on standard error | Receives one event per tool call. |
Related
Section titled “Related”- Quickstart: the
supportgraph these examples use. - Search by meaning: embeddings, filters and search planning.
- Query and validate: SPARQL and SHACL in depth.
- Reasoning & inference: the
entailmentregimes. - Replay an answer: pin a read to a commit and replay it.