@littlebigbrain/mcp
This MCP server lets you search, query, write, and manage little big brain graph data, schemas, embeddings, evals, and models.
Inspect graph context: schema, ontology, publication, metadata, entities, conformance, and ontology suggestions.
Query data by plain-language question, SPARQL, structured JSON, semantic search, or analyze mode; supports entailment, strong consistency, pagination, and commit snapshots.
Import RDF (Turtle/N-Triples/N-Quads/TriG) or add facts with SPARQL INSERT DATA; no named graphs or deletions.
Write or retract JSON facts, typed properties, and search feedback with idempotency.
Manage embeddings: inspect setup, preview text, declare/refresh/change model, delete.
Configure native ontology/SHACL: define/evolve schema, apply starters, publish validation, suggest changes, manage rewrite profiles.
Run managed evals: label results, create/run goldens, judge, inspect checks, review model checks.
Read model activity, shadow-eval retrieval configs, and training datasets.
Connect via hosted OAuth or local stdio, or embed in a Node.js process.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@littlebigbrain/mcpsearch for entities related to 'Project Apollo'"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@littlebigbrain/mcp
Model Context Protocol (MCP) server for little big brain, a search platform for AI applications such as chatbots, search tools, and agents.
Connect an MCP client to search your data, follow relationships, and read the facts behind an answer. The tools also let you load data and define validation rules.
Documentation · Quickstart · Issues
Connect
Create a stack in the console, then choose a hosted connection or a local process.
Hosted connection
For clients that support remote MCP with OAuth, use this URL and sign in with
your little big brain account. Replace <stack-slug> with your stack's slug:
https://mcp.littlebigbrain.com/mcp/<stack-slug>For clients that use an mcpServers JSON configuration:
{
"mcpServers": {
"lbb": {
"url": "https://mcp.littlebigbrain.com/mcp/<stack-slug>"
}
}
}This connection uses account sign-in and does not require a stack API key.
The connection guide
includes client-specific setup, including the origin URL and X-LBB-Stack header
for Codex.
Local process
Requires Node.js 18+. Copy the complete endpoint and a stack API key from Connect in the console, then add them to your client's MCP configuration:
{
"mcpServers": {
"lbb": {
"command": "npx",
"args": ["-y", "@littlebigbrain/mcp"],
"env": {
"LBB_BASE_URL": "https://<your-complete-stack-host>",
"LBB_API_KEY": "<your-stack-api-key>"
}
}
}
}The client starts the server and communicates through standard input and output
(stdio). Keep the key in your local configuration. Set LBB_GRAPH to change
the default graph from main.
Related MCP server: RDF4J MCP Server
Run a first query
This example stores three facts in a graph named quickstart: a service writes
to a database, and each has a label. The graph is created on its first write.
Ask your client to call lbb_rdf with these arguments:
{
"action": "import",
"graph": "quickstart",
"format": "ntriples",
"source": "<https://example.org/auth-service> <https://example.org/writesTo> <https://example.org/user-db> .\n<https://example.org/auth-service> <http://www.w3.org/2000/01/rdf-schema#label> \"Auth Service\" .\n<https://example.org/user-db> <http://www.w3.org/2000/01/rdf-schema#label> \"User Database\" .",
"idempotency_key": "mcp-quickstart-v1"
}Now ask which database does Auth Service write to? The lbb_query call is:
{
"mode": "sparql",
"graph": "quickstart",
"consistency": "strong",
"query": "SELECT ?database WHERE { <https://example.org/auth-service> <https://example.org/writesTo> ?db . ?db <http://www.w3.org/2000/01/rdf-schema#label> ?database } ORDER BY ?database LIMIT 10"
}The result contains one row on a fresh graph:
database |
User Database |
The query follows a stored relationship to its database label. Strong consistency lets it read the import without waiting for a background index job.
An agent without a SPARQL query can pass the question in plain words:
{
"mode": "question",
"graph": "quickstart",
"question": "Which database does Auth Service write to?"
}The server answers in plain words (POST /v1/query/ask). A router model picks
the kind of question. A reasoning model runs queries in a bounded loop, reads
their rows, and answers. The result holds answer (text, citations, the
IRIs the answer names, and chart, how to draw the rows, when the server
gave one), steps, the route, and the query and rows the answer stands on. next continues that query with mode: "sparql". A
question takes about 8 s. Each question uses model tokens and counts toward a
daily limit of the stack, so the tool does not retry a failed call.
The server finds the names in the question in the graph and lists them in
linked. When the question is about records you already know, pass their
IRIs in anchor (at most 10): the queries use them directly. A question
about a date reads the last commit written by the end of that day; pass
timeline ([{date, as_of_commit_seq, label?}]) when the commits stand for
other dates. A question that asks what changed returns history.added,
history.removed and history.changed, with history.totals.
When the tool call carries a _meta.progressToken, the server sends a
progress notification for each step, for example Route: lookup (router, 0.92) or Step 2, sparql SELECT ?db: 1 row. The result is the same. Cancel
the call to stop the server's work.
To write the queries yourself, use names, describe, commit_at and
compare, then mode: "sparql".
For your own data, start with lbb_inspect using action: "guide" or
action: "ontology". Imported Resource Description Framework (RDF) data keeps
its original identifiers; inspect it with SPARQL when choosing query predicates.
Tools
Tool | Purpose |
| Read the schema, graph status, and entities. |
| Ask a question in plain words, run SPARQL queries, search by meaning (also inside a SPARQL query with |
| Import RDF documents or add facts with SPARQL |
| Inspect search setup and preview the text to embed. |
| Set up or refresh embeddings, or change the embedding model. |
| Delete an embedding and its stored vectors. |
| Inspect fit from text and preview the text the fit reads. |
| Declare, dry-run or refresh a fit source. |
| Delete a fit source; its suggestions stay. |
| List the starter workflows this server offers and the workflows created from them on a graph (triggered workflows), read one with its status, and preview a new one. |
| Create a workflow from a starter workflow on a class (a developer workflow with its workflow type, owned outputs and batch), ask it to run now, or pause and resume a developer workflow. |
| Delete a triggered workflow. What it wrote stays. |
| List the files of a graph, and read the parsed pages of one: each line with its id, its box on the page and its text. |
| Write or retract JSON facts, or record search feedback. |
| Define record types and relationships, list and apply ontology starters (CRM, documents, work), publish validation rules, or keep the graph's notes and worked examples for questions in plain words ( |
| Label query results and check whether later queries return the expected answers. Read the model checks of a graph, and agree with or correct a check that the user confirmed. |
| Read which model each use runs (question answers, query routing, search rerank, ontology fit, eval labels), and the trials that test other models against the graph's ground truth. |
| Start or stop a trial, switch a use to a tested model that meets the bar, or revert to LBB's model. |
| Compare retrieval settings, read model training datasets, or read a month of managed-model activity. |
See search by meaning for embedding setup. To define constraints with the Shapes Constraint Language (SHACL), see query and validation.
RDF imports and JSON facts use different write workflows. A graph first written
through lbb_rdf does not accept JSON fact writes through lbb_commit. Choose
the workflow when creating the graph. RDF updates
support additive INSERT DATA;
see the RDF guide for format and
update limits.
Pages and saved queries
When a result includes next, pass those arguments to the same tool to read the
next page. Continue until next is absent. row_limit sets a maximum; large
values can make a page shorter.
SPARQL queries keep the same commit across pages. Save the query and its returned
commit sequence to check an answer later, then use as_of_commit_seq to select
that version. See history and replay
for retention and evidence handling.
Embed the server
To serve the tools from your own Node.js process:
import { createMcpHttpServer } from "@littlebigbrain/mcp";
createMcpHttpServer({
baseUrl: process.env.LBB_BASE_URL!,
mcpPath: "/mcp",
allowedHosts: ["127.0.0.1", "localhost", "::1"],
}).listen(8080, "127.0.0.1");Clients connect to http://127.0.0.1:8080/mcp and send a stack API key in
Authorization: Bearer <key>. See the
Node.js integration guide
for HTTP options and integration with an existing MCP server.
Development
From a clone of this repository:
npm ci
npm run build
npm run typecheck
npm testLicense
Available Tools
10 toolslbb_commitAIdempotent
Write graph facts, retract them, or label ranked results. mode=facts writes triplets/embeddings/properties; mode=retract removes a wrongly-added fact (by edge or by entity) without a full reset; mode=search_feedback stores query/result relevance labels (Feedback grades: 3=ideal/good, 1=partial, 0=bad; include query, search_id when available, target, rank, score). Explicit idempotency_key wins; when omitted, MCP derives a stable content hash so content-identical retries dedupe. Facts mode defaults edge_idempotency to append; pass skip_unchanged for re-runnable backfills.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | ||
| graph | No | Graph to target; defaults to the connection's graph | |
| dry_run | No | Validate a facts commit and return its structured SHACL report without writing. Only supported for mode=facts. | |
| triplets | No | ||
| observed_at | No | Backfill timestamp (RFC3339). Records this commit AS OF that instant: stamps transaction time and defaults each triplet's valid_time.start. Replay history in order with observed_at per commit so as-of reads by date work. Omit for live writes. | |
| retract_edges | No | mode=retract: specific edges to remove, matched by (source, relation, target). | |
| idempotency_key | No | ||
| search_feedback | No | ||
| edge_idempotency | No | Defaults to append in MCP. Use skip_unchanged for backfills; it skips exact current-edge duplicates and drops evidence-only repeats. | |
| retract_entities | No | mode=retract: entities whose every current edge is removed (a current-state tombstone; the record and its history are kept for as_of reads). | |
| entity_embeddings | No | ||
| entity_properties | No | Typed scalar attributes per entity. Each item is { type, name, properties }. `properties` is a flat map of field -> value, e.g. { "type": "PERSON", "name": "Ada Lovelace", "properties": { "h_index": 52, "title": "VP", "last_contact": "2026-06-26" } }. Values are coerced to each field's declared type, so a string like "2026-06-26" lands in a date_time field and "52" in an i64 field. (The verbose form [{ field, value: { i64: 52 } }] is also accepted.) Register a field first with lbb_configure evolve_ontology add_property; the commit response echoes written_properties so you can confirm what landed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description adds valuable behavior: explicit idempotency_key wins, omitted keys derive a stable content hash for dedupe, facts mode defaults to append, and retract supports both edge and entity removal. It does not spell out every side effect in the top-level text, but the schema covers tombstone/history preservation for retract_entities.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but economical: five sentences front-load the mode enum, then cover idempotency, feedback grading, and backfill defaults without repetition or filler. Every clause adds operational value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 12-parameter tool with no output schema, the description covers mode semantics, idempotency, dry_run, backfill timestamps, and feedback labels well. However, mode itself is not required in the schema and the description never states what happens when mode is omitted, nor what the commit returns. Those gaps matter for an agent deciding whether and how to invoke the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description meaningfully explains the mode enum, idempotency semantics, edge_idempotency behavior, and even the feedback grading scale. Combined with schema descriptions for dry_run, observed_at, retract_edges, and entity_properties, most parameters are actionable. Some params like triplets and entity_embeddings rely on mode prose rather than dedicated descriptions, but the context is sufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Write graph facts, retract them, or label ranked results.' It then enumerates three distinct modes with concrete behaviors, making the tool immediately distinguishable from read/schema siblings like lbb_query and lbb_configure.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly says when each mode is appropriate: retract is for removing wrongly-added facts without a full reset, search_feedback is for storing relevance labels, and skip_unchanged is for re-runnable backfills. It also indirectly points to lbb_configure for registering fields. It stops short of a fully explicit when-not-to-use or comparison with every sibling, so it is not a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_configureA
Manage native schema metadata. Actions: define_ontology (friendly spec with super_types), evolve_ontology (ordered edits including add_super_types), list_starters (the base ontologies crm, documents and work, each with its status on the graph: absent, partial or applied, what applying adds, and conflicts), apply_starter (add what the graph lacks of a starter in one ontology version; a relation the graph has is widened; refused with starter_conflict when the graph holds a term differently; dry_run previews), publish_schema (SHACL activation), suggest_ontology_change (file a change for a person to review instead of applying it; prefer it when the graph's owner reviews ontology changes, and list the result with lbb_inspect action=ontology_suggestions), get_rewrite_profile and set_rewrite_profile (the graph's notes and up to 20 worked question-to-SPARQL examples that lbb_query mode=question reads for every question; pass the version you read as expected_version). define, evolve, publish and set_rewrite_profile support dry_run previews. Definition/import here extracts native metadata; it does NOT store the complete RDF/OWL document as queryable graph facts. Use lbb_rdf import for full OWL and lbb_rdf update for additive INSERT DATA revisions; RDF deletions are unsupported. Publish_schema accepts unchanged ontology plus shapes; use define/evolve for native ontology changes. Publication enqueues durable conformance; a preview does not validate the whole graph.
| Name | Required | Description | Default |
|---|---|---|---|
| key | No | Idempotency key ([A-Za-z0-9-_.:/]); filing again with the same key revises the suggestion | |
| ops | No | Ontology changes to apply in order (additive, in-place edits, or subtractive) | |
| agent | No | Your name as the producer, shown to reviewers | |
| graph | No | Graph to create or redefine | |
| notes | No | What the data means for questions: which property holds the current state, what 'me' or 'my' means, which records to leave out. At most 8,000 characters | |
| title | No | Short imperative text, e.g. 'Add class Contractor' | |
| action | Yes | Selects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change, get_rewrite_profile, set_rewrite_profile). | |
| anchor | No | The class, property or relation the change is about | |
| change | No | The ontology operations a person applies by accepting, in order (same shapes as evolve_ontology ops) | |
| format | No | ||
| shapes | No | ||
| source | No | ||
| dry_run | No | Preview the exact definition without creating a graph or writing metadata. | |
| starter | No | Starter id: crm, documents or work (list_starters names them) | |
| evidence | No | What you saw: record count, fields, up to 20 sample records | |
| examples | No | Up to 20 worked examples: a question and the query that answers it on this graph | |
| ontology | No | ||
| rationale | No | Why the ontology needs the change; cite what you saw | |
| relations | No | ||
| desired_mode | No | ||
| entity_types | No | ||
| merge_default | No | ||
| expected_version | No | The version get_rewrite_profile returned (0 for none): another stored version answers 409 conflict and stores nothing | |
| confirm_restrictive | No | ||
| allow_data_conflicts | No | Deprecated compatibility flag; does not bypass conflicts. Preview subtractive changes with dry_run=true, repair the reported conflicts, then apply. | |
| expected_ontology_version | No | Refuse when the graph's ontology version differs |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: dry_run previews on define/evolve/publish/set_rewrite_profile, starter_conflict refusal semantics, widening vs. refusing on apply_starter, and 'publication enqueues durable conformance; a preview does not validate the whole graph.' It also discloses a key negative behavior — that definition/import does NOT store the full RDF/OWL document as queryable facts.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and every clause carries information, but the action list is delivered as one very dense, parenthetical-laden block that is hard to scan for a single action. For an eight-action, 26-parameter tool the length is defensible, yet some sentences (e.g., the apply_starter clause) are run-ons.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For eight actions and 26 parameters with no output schema, the description covers behavior, routing, safety and dry-run semantics well. It is less complete on define_ontology's own parameter surface (entity_types, relations, merge_default, confirm_restrictive, desired_mode), which the agent must learn from the schema alone.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 65% schema description coverage, the schema carries much of the load, but the description adds real meaning for several parameters: it tells the agent to pass the version read from get_rewrite_profile as expected_version, that starter accepts only crm/documents/work, and what the rewrite-profile notes/examples are for. Many parameters (ops, change, anchor, merge_default, desired_mode) remain schema-only, so it does not fully compensate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Manage native schema metadata') and then enumerates all eight actions with what each does, including distinct scope for list_starters, apply_starter and suggest_ontology_change. It explicitly distinguishes itself from siblings lbb_rdf and lbb_inspect, so an agent can route correctly without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing guidance: 'Use lbb_rdf import for full OWL and lbb_rdf update for additive INSERT DATA revisions; RDF deletions are unsupported,' and 'prefer it [suggest_ontology_change] when the graph's owner reviews ontology changes.' It also states when define/evolve should be used instead of publish_schema. Alternatives and conditions are named, not inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_embeddingsARead-only
Search setup, read only: embeddings declared on classes (an embedding on a class covers its subclasses; one model per graph). list shows each embedding's status (serving and building version, backfill progress, lag) and the graph's model; get shows one; preview shows every candidate fact of a class with its coverage and examples, and the exact text of sample instances, and stores nothing. Declare, refresh, or change the model with lbb_embeddings_manage; search with lbb_query mode=search. list is the first step of planning a search (lbb_inspect action=guide has the recipe).
| Name | Required | Description | Default |
|---|---|---|---|
| dim | No | ||
| from | No | preview/declare: the fields, e.g. ["label", "description", "calls/label"]. Omit for the automatic choice; on an existing embedding, omit to keep its fields. | |
| iris | No | preview: the instances to show instead of a sample. | |
| name | No | get: the embedding name. | |
| class | No | preview/declare: the class IRI. | |
| graph | No | Graph to target; defaults to the connection's graph | |
| model | No | model: the graph's new model. preview/declare: omit it; a graph has one model (the graph's, or the platform's default for the first embedding). | |
| title | No | preview/declare: the field that names each hit, e.g. "display_name". Omit for the ontology's name property (skos:prefLabel, a property declared rdfs:subPropertyOf rdfs:label, else rdfs:label); on an existing embedding, omit to keep its name. preview reports title_source and, when the labels read as keys, title_suggestion. | |
| action | Yes | ||
| detail | No | Response detail level. Defaults to compact. | |
| sample | No | ||
| exclude | No | preview/declare: fields to drop from the automatic choice. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description adds valuable context: preview 'stores nothing', embeddings on a class cover subclasses, and one model per graph. It also explains the status fields shown by list and the exact behavior of preview. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a dense single paragraph, front-loaded with 'Search setup, read only'. It packs key facts (coverage semantics, action outputs, alternative tools) without excessive verbosity, though it could be broken into shorter sentences for easier scanning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 12 parameters and no output schema, the description covers the main actions and clarifies core semantics, but omits details on dim, sample, detail, and exclude. It also does not describe return formats, leaving some agent decisions to inference. Adequate but not fully comprehensive.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75% (missing descriptions for dim, sample, and action). The description explains the action parameter implicitly through list/get/preview and references class/name, but it does not clarify dim or sample. It partially compensates for the schema gap but leaves two parameters ambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Search setup, read only' for embeddings, and differentiates the three actions (list, get, preview) with distinct behaviors. It also names sibling tools (lbb_embeddings_manage, lbb_query) to avoid ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use this tool: 'list is the first step of planning a search' and provides the recipe location (lbb_inspect action=guide). It also directs mutation tasks to lbb_embeddings_manage and search to lbb_query, making the usage boundary clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_embeddings_deleteADestructiveIdempotent
Delete an embedding: its name and its vectors (index-gc removes the stored runs). Its class stops being searchable until it is declared and built again. Ask the user first; confirm must repeat the name.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | The embedding name. | |
| graph | No | Graph to target; defaults to the connection's graph | |
| detail | No | Response detail level. Defaults to compact. | |
| confirm | Yes | The same name again, to confirm. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark destructiveHint=true and idempotentHint=true, but the description adds valuable context: index-gc removes stored runs and the embedding class becomes non-searchable until rebuilt. This discloses side effects beyond the annotation flags and does not contradict any annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences with no wasted words. The primary action is front-loaded, and subsequent sentences add crucial details (index-gc, searchability, user confirmation) in a logical order. It is efficient yet thorough.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive operation with four parameters and no output schema, the description covers what happens (deletion, vector removal, searchability impact) and the required confirmation flow. It gives an agent everything needed to invoke it correctly and understand the consequences, making it complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with detailed parameter descriptions, so the schema already explains each parameter. The description adds context about the confirm requirement and its effect, but those are already present in the schema's description for 'confirm'. It does not introduce new parameter-level semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action (delete an embedding) and its effects (removes name and vectors, stops searchability). It goes beyond a simple verb+resource by explaining the consequence that the class must be redeclared and rebuilt, making the purpose unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit guidance on usage: ask the user first and require confirmation via repeating the name. It does not compare directly with sibling tools like lbb_embeddings_manage, but the unique destructive nature and safety instructions provide clear context for when it should be used.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_embeddings_manageA
Declare or refresh an embedding, or change the graph's model. Run lbb_embeddings action=preview first and show the user the text it will embed. declare sets the class, the fields (one-hop property paths such as label, description, calls/label; omit for an automatic choice); a new embedding takes the graph's model, and another model is refused. On an existing embedding it changes only what you name, and a changed recipe builds a new version while the old one serves. model moves every embedding of the graph to model: each builds a new version, and the graph switches when all are ready (a search never mixes two models). refresh runs one step of the embed job now (it also runs by itself after each published commit).
| Name | Required | Description | Default |
|---|---|---|---|
| dim | No | ||
| from | No | preview/declare: the fields, e.g. ["label", "description", "calls/label"]. Omit for the automatic choice; on an existing embedding, omit to keep its fields. | |
| name | No | The embedding name (refresh: required). | |
| class | No | preview/declare: the class IRI. | |
| graph | No | Graph to target; defaults to the connection's graph | |
| model | No | model: the graph's new model. preview/declare: omit it; a graph has one model (the graph's, or the platform's default for the first embedding). | |
| title | No | preview/declare: the field that names each hit, e.g. "display_name". Omit for the ontology's name property (skos:prefLabel, a property declared rdfs:subPropertyOf rdfs:label, else rdfs:label); on an existing embedding, omit to keep its name. preview reports title_source and, when the labels read as keys, title_suggestion. | |
| action | Yes | ||
| detail | No | Response detail level. Defaults to compact. | |
| exclude | No | preview/declare: fields to drop from the automatic choice. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations only say non-read-only and non-destructive; the description adds crucial behavior: a changed recipe builds a new version while the old one serves, the graph switches only when all versions are ready so searches never mix models, and a differing model is refused. This is substantial transparency beyond the flags.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but front-loaded: overview first, then the preview prerequisite, then action-by-action behavior. Every sentence carries distinct information and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with ten parameters, three actions, and no output schema, it thoroughly covers action semantics and constraints. The main gaps are the undocumented dim parameter and the meaning of the detail response levels.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already documents most parameters, and the description adds extra meaning by defining from as one-hop property paths and explaining how model relates to graph-wide behavior. However, dim is undocumented in both the schema and description, so it falls short of 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence names the three distinct actions with a verb and resource: declare/refresh an embedding or change the graph's model. This distinguishes it from lbb_embeddings_delete and from lbb_embeddings, which the description itself points to for preview.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit precondition: run lbb_embeddings action=preview first and show the user the text. It also explains when declare can use the graph's model, when refresh is appropriate, and that refresh also runs automatically after published commits.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_evalsA
Managed evals: the thumbs up / thumbs down of the graph, per result. A query run with request (lbb_query) records a trace with one item per result (hit or row); trace reads it back with the item ids. label marks one result (item + valid) or several (items) relevant or not; the labels become the golden's ground truth. golden freezes a query (every result it returns now is relevant). run replays every golden at the current commit: pass when every relevant result is back and no wrong one is; new results open a review trace. judge lets the platform's judge model (the hosted frontier model) label unlabeled results. summary, traces, goldens, results, and settings read state. Model checks: a judge model checks a sample of the model calls LBB makes for the graph (rerank, route, rewrite, fit, propose, label). checks_summary reads a month per job and model (checks, score, right, partly, wrong, reviews) and the judge's agreement with people; checks lists the month's checks, newest first, with the judge's verdict, score and reason and the ground truth (truth). review_check records a person's review of one check (call_id): agree=true keeps the judge's verdict; agree=false with verdict (and an optional score, reference and note) corrects it. The review becomes the call's ground truth, so show the check to the user and review only what the user confirmed.
| Name | Required | Description | Default |
|---|---|---|---|
| by | No | label: who labels (an agent name). | |
| job | No | checks: only the checks of one job. | |
| item | No | label: the result id (a hit's `id`, or an item id from trace) to label with `valid`. | |
| note | No | label / review_check: why. review_check: at most 2,000 characters. | |
| after | No | checks: the next_after of the previous page. | |
| agree | No | review_check: true = the judge is right, false = correct it with verdict. | |
| graph | No | Graph to target; defaults to the connection's graph | |
| items | No | label: several results at once. | |
| limit | No | ||
| month | No | checks_summary / checks: the month, yyyy-mm (UTC). Defaults to the current month. | |
| score | No | review_check with agree=false: the right score, 0 to 1. Omit for the judge's score of that verdict. | |
| top_k | No | golden: the top_k of a search golden. | |
| valid | No | label: true = the result answers the request (thumbs up), false = it does not. | |
| action | Yes | ||
| detail | No | Response detail level. Defaults to compact. | |
| sparql | No | golden: the query to freeze (the search text for surface=search). | |
| call_id | No | review_check: the check's `call` id, from checks. | |
| request | No | golden: the user's words the query answers. | |
| surface | No | golden: which surface the query runs on (default sparql). | |
| verdict | No | checks: only the checks whose ground truth has this verdict. review_check with agree=false: the right verdict. | |
| reviewed | No | checks: true = only the checks a person reviewed, false = only the others. | |
| trace_id | No | trace / label / judge: the trace id from lbb_query. | |
| embedding | No | golden: the embedding, for surface=search. | |
| golden_id | No | accept / delete: the golden id. | |
| reference | No | review_check with agree=false: the right answer. A rerank or label check: {"grades": {"<hit id>": 0..3}}; a route or fit check: {"picks": {"<question id>": "<option>"}}. | |
| unlabeled | No | traces: only traces without a label. | |
| consistency | No | run / accept: strong reads the head, eventual the last published commit. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations only covering readOnly/destructive/openWorld, the description carries real behavioral weight: labels 'become the golden's ground truth', a golden 'freezes a query (every result it returns now is relevant)', a run 'passes when every relevant result is back and no wrong one is', and 'the review becomes the call's ground truth'. Those are state-effect disclosures the annotations cannot express. It omits, however, any mention of the accept/delete actions or their effects, and gives no auth or rate-limit context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Roughly 330 words for 15 actions is defensible in size and the core concept is front-loaded, but it is delivered as a single dense block of semicolon-chained clauses with no per-action structure. Scanning for a specific action such as review_check requires reading through unrelated eval prose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 27-param, 15-action multiplexer with no output schema, the description covers the substantive workflow and even names the fields checks_summary returns (checks, score, right, partly, wrong, reviews). Gaps remain: accept and delete are never described beyond the schema's 'the golden id', and five read actions are compressed into one clause ('summary, traces, goldens, results, and settings read state').
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 93%, so the baseline is 3, but the prose adds meaning the schema does not: it explains that 'label marks one result (item + valid) or several (items)' — clarifying the single-vs-batch alternative — and that trace_id comes 'from lbb_query'. It also frames verdict/score/agree as a correction triple for review_check. Remaining params (limit, detail, graph, golden_id) get no description-level treatment.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a concrete verb+resource for nearly every action: 'label marks one result ... relevant or not', 'golden freezes a query', 'run replays every golden at the current commit', 'review_check records a person's review of one check'. An agent can map the 15 enum values to distinct purposes. Sibling differentiation is thin, though: lbb_query is named only as the source of trace ids, and no contrast is drawn with lbb_models despite the overlapping 'Model checks' section.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is mostly implied through the described eval workflow (label -> golden -> run -> review), rather than stated as when-to-use. Only one explicit operational directive is given: 'show the check to the user and review only what the user confirmed.' There are no when-not conditions and no routing guidance against the sibling tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_inspectARead-only
Read graph context and exact graph facts. Actions: guide, graphs, publication, ontology, ontology_conformance, schema, ontology_search, metadata, entity, ontology_suggestions. graphs works before bootstrap; ontology_suggestions lists the ontology change suggestions that wait for review (or were decided). publication reports whether writes are queryable. ontology and schema return complete entries with page_size, section and cursor; follow next until absent. schema reads active native ontology/SHACL metadata without running validation. Query asserted RDF/OWL axioms separately with lbb_query. ontology_conformance serves the durable report referenced by the pinned published root. entity returns one node's attributes and current relationships from the RDF read. For a node's past values, run SPARQL with as_of_commit_seq through lbb_query. Use lbb_query with SPARQL property paths for precise path selection.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | ||
| as_of | No | Unsupported for entity; use as_of_commit_seq for a retained commit snapshot. | |
| graph | No | Graph to target; defaults to the connection's graph | |
| limit | No | ||
| query | No | Ontology concept, term, or relation to search | |
| top_k | No | ||
| action | Yes | Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, ontology_suggestions, entity). | |
| cursor | No | Opaque lbb_inspect continuation. Repeat action and pass the returned next arguments; rejects changed metadata. | |
| detail | No | Response detail level. Defaults to compact. | |
| status | No | Only suggestions in this state; default all | |
| section | No | Optional top-level array to inspect, e.g. entity_type_defs, relation_defs, property_defs, classes, or relations. Omit to page through all sections. | |
| entity_id | No | Entity id (hex); alternative to entity_type+name | |
| page_size | No | Maximum complete metadata entries per page; defaults to 50. Nested fields are never truncated; an oversized single entry returns serialized_json fragments to concatenate and parse. | |
| entity_type | No | ||
| as_of_commit_seq | No | Snapshot pin: reproduce the node's attributes and relationships as of this commit_seq. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With readOnlyHint=true already covering the safety profile, the description still adds real behavioral context: pagination contract ('follow next until absent'), cursor semantics ('rejects changed metadata'), oversized-entry fragmentation into serialized_json, that 'publication reports whether writes are queryable', and that ontology_conformance serves a durable report pinned to the published root. It does not describe permissions, rate limits, or failure modes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The content is proportionate to a 10-action, 15-parameter dispatcher, and the action inventory is front-loaded. However it is delivered as one dense unstructured block with no bullets or line breaks, and the action list partly duplicates the schema's action enum description, so it is harder to scan than it needs to be.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema and no nested objects, so the description carries the return-shape burden and does so for most actions (pagination, fragment reassembly, entity output, publication flag). It omits what guide, metadata, and ontology_search return, and never explains the query/top_k search parameters, leaving a few gaps for a tool this broad.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 73% and the action enum is already self-documenting in the schema, but the description adds substantial semantic meaning: it explains what each action returns (ontology/schema give complete entries with page_size/section/cursor; entity returns attributes and current relationships) and reinforces that as_of is unsupported for entity. It leaves limit, detail, top_k and metadata unaddressed in prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb+resource ('Read graph context and exact graph facts') and then enumerates the ten specific inspection resources (guide, graphs, publication, ontology, schema, entity, etc.). It explicitly distinguishes itself from the sibling lbb_query twice ('Query asserted RDF/OWL axioms separately with lbb_query', 'Use lbb_query with SPARQL property paths'), so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives per-action usage context (e.g., 'graphs works before bootstrap', 'ontology_suggestions lists the ontology change suggestions that wait for review', 'For a node's past values, run SPARQL with as_of_commit_seq through lbb_query'). It clearly names alternatives for the read-vs-query decision, though it never contrasts itself with other read siblings like lbb_rdf or lbb_models, and the other nine sibling tools go unmentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_modelsARead-only
Read model-training inputs or compare retrieval configurations over one pinned published snapshot, or read what the managed models did. shadow_eval takes the API ShadowEvalRequest body; dataset actions return bounded training examples at an optional signal split. activity reads one month of the stack's model use (all graphs): calls, items, estimated tokens and cost per feature (index, search, fit, judge, training) and model, by day and by graph, the months with activity, and the model each feature uses now.
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | ||
| graph | No | Graph to target; defaults to the connection's graph | |
| limit | No | ||
| month | No | activity: the month, yyyy-mm (UTC). Defaults to the current month. | |
| action | Yes | ||
| detail | No | Response detail level. Defaults to compact. | |
| split_seq | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and the description is consistent, framing everything as reads. It goes beyond the annotation by disclosing return content shape: bounded training examples, a one-month window, and per-feature/per-model/per-day cost and token breakdowns. It does not cover pagination or default detail behavior beyond what the schema states.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence front-loads the tool's scope well, but the final sentence is a long comma-chained run-on enumerating features, dimensions, and defaults, which is harder to parse than necessary. Information density is high, but structure could be tightened with per-action sentences or a list.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter multiplexed tool with no output schema and 43% schema coverage, the description covers the action semantics reasonably but leaves required agent knowledge gaps: graph targeting, limit behavior, and detail-level effects are unexplained, and no return envelope for shadow_eval is described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 43%, so the description must compensate. It does explain `body` (ShadowEvalRequest for shadow_eval), implies `split_seq` via 'at an optional signal split', and covers `month` semantics for activity, but leaves `graph`, `limit`, and `detail` to the schema, which documents only the first two.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names concrete verbs and resources: reading model-training inputs, comparing retrieval configurations over a pinned published snapshot, and reading managed-model activity. It separates the four action modes (shadow_eval, the two dataset actions, activity) so an agent can tell what the tool covers, though it never contrasts itself against the similarly named lbb_evals or lbb_query siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It implies usage per action (shadow_eval takes an API ShadowEvalRequest body; dataset actions return bounded training examples at a signal split; activity reads one month of model use), which helps pick an action value. However, there is no guidance on when to choose this tool over sibling tools like lbb_evals or lbb_query, and no stated prerequisites.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_queryARead-only
Analytical and expert reads. Modes: question (a question in plain words), structured (SPARQL-subset JSON body), sparql (SPARQL text), search (instances by meaning over every searchable class; filter narrows by class and relationship; every hit checked against the graph), analyze. Use mode=question when you have a question in plain words and no SPARQL query: the server selects the kind of query (route), writes the SPARQL query from a description of the graph, checks it, runs it, and returns the route, the rationale, the query and its rows. Continue or correct that query with mode=sparql. Each question uses model tokens and counts toward a daily limit of the stack. SPARQL is the query language; search finds what the words describe. SPARQL text can also search by meaning inside the query with ?x https://littlebigbrain.com/search#similarTo "words", so the other patterns filter and join the hits in one query; the result's search field reports the plan. To plan a search: lbb_embeddings action=list, then SPARQL for a class's relationships on a sample, then mode=search with explain=true to check the resolved filter before the real search (lbb_inspect action=guide has the queries). Relations are https://littlebigbrain.com/r/NAME and types https://littlebigbrain.com/class/NAME (both lowercased); entities are content-addressed, so anchor a named one by its rdfs:label rather than building its IRI. Structured and text queries pin one published watermark for the request.
| Name | Required | Description | Default |
|---|---|---|---|
| run | No | question: run the query and return its rows. Defaults to true; false returns the query only. | |
| body | No | Structured SPARQL-subset request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: "x" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { "compare": { "op": <op>, "left": <term>, "right": <term> } } (or { "and": [<filter>…] }, { "or": [<filter>…] }, { "not": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { "var": "x" }, { "property": { "var": "x", "field": "amount" } } (a typed scalar attribute), or { "value": <typed> } — and <typed> is exactly one wrapper: { "str": "…" }, { "i64": 5 }, { "f64": 0.9 }, { "bool": true }, { "date_time": "2026-01-01" } (RFC3339), or { "entity": { "entity_type": "T", "name": "N" } }. Complete runnable example — deals whose amount ≥ 1000000: { "patterns": [{ "subject": { "var": "d" }, "predicate": "for_client", "object": { "var": "c" } }], "filters": [{ "compare": { "op": "ge", "left": { "property": { "var": "d", "field": "amount" } }, "right": { "value": { "f64": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: ["s"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { "patterns": [{ "subject": { "var": "c" }, "predicate": "committed_to", "object": { "var": "repo" } }], "group_keys": [{ "date_bucket": { "var": "c", "field": "committed_at", "granularity": "month", "as": "m" } }, { "property": { "var": "c", "field": "area", "as": "area" } }], "aggregates": [{ "func": "count", "as": "n" }], "order_by": [{ "var": "m" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { "compare": { "op": "gt", "left": { "var": "n" }, "right": { "value": { "i64": 10 } } } }). A `combinators` key (UNION/OPTIONAL/MINUS/EXISTS) is rejected here; express those with SPARQL text under mode=sparql. Cheap aggregate count: pair an equality having (e.g. { "compare": { "op": "eq", "left": { "var": "n" }, "right": { "value": { "i64": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning use the top-level `as_of_commit_seq` argument or the same body field. Valid-time `as_of` and `as_of_valid_time` selectors are unsupported and rejected before HTTP. | |
| mode | Yes | Selects the variant (one of: structured, sparql, question, search, analyze). | |
| text | No | The query text (required); embedded with the graph's model. | |
| as_of | No | Unsupported in structured and SPARQL text modes; use as_of_commit_seq for a retained commit snapshot. | |
| chart | No | ||
| field | No | ||
| graph | No | Graph to target; defaults to the connection's graph | |
| limit | No | question: rows the run returns, 1 to 1,000. Defaults by detail: compact=20, standard=100, full=1000. | |
| probe | No | Clusters to read (default 4·√clusters, at least 8). More reads cost latency and find more. | |
| query | No | SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> "Acme"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10. Search by meaning inside the query (the graph needs an embedding; see lbb_embeddings action=list): PREFIX search: <https://littlebigbrain.com/search#> SELECT ?x ?score WHERE { ?x search:similarTo "card payments" ; search:score ?score . ?x <https://littlebigbrain.com/r/calls> ?y } ORDER BY DESC(?score) LIMIT 5. The other patterns filter and join the hits. One search:similarTo per query, with a variable subject, in the main group (not inside OPTIONAL, UNION, MINUS or a subquery). The object is text, an entity IRI (records like that one) or a vector literal. search:top N sets the hits (1 to 1000; default the query LIMIT, then 10) and search:embedding "name" searches one embedding. FILTER(?score > 0.8) keeps close hits. The result's search field reports the plan (nearest, filter_first or search_first), the hits and complete. For a question in words, add search:rerank true ; search:relevance ?r and ORDER BY DESC(?r): the rerank model (Jev) reads the best hits with the text, keeps the top that answer it and binds its answer (0 to 1); search.rerank reports the status. Only a text query reranks. | |
| route | No | question: the kind of query, when you know it. Omit it and the router model selects it. | |
| top_k | No | ||
| anchor | No | question: entity IRIs the question is about, at most 10 (for example the record the user has open). The server reads each one, and the query uses these IRIs directly instead of matching their names. | |
| cursor | No | Opaque cursor from a previous lbb_query row page; reruns the original query at the next offset. | |
| detail | No | Response detail level. Defaults to compact. | |
| filter | No | Conditions every hit must meet: {"class": …} or {"via": …, "to": …}. The response's filter shows how each condition resolved; an unknown relationship or name answers with the options. | |
| metric | No | ||
| rerank | No | true: the managed rerank model (Jev) orders the best hits by how well each answers the text, and each hit gets its relevance (0 to 1); adds about 0.3 s. false: the similarity order. Omit it to follow the graph's search setting. | |
| sparql | No | ||
| context | No | question: notes for the model, at most 8,000 characters: what the data means, units, names to prefer. | |
| explain | No | Plan without running: the scope, the resolved filter, and the allowed count. No model call. | |
| include | No | text: return the embedded text of each hit. | |
| request | No | The user's own words behind this query (managed evals). When present the server records an eval trace and the result carries its trace_id; label the rows valid or not with lbb_evals action=label. Omit on continuation pages. | |
| question | No | question: the question in plain words (required), 1 to 4,000 characters. The server writes the SPARQL query from a description of this graph, checks it, and runs it. | |
| timeline | No | question: dated points that stand for the graph's commits, at most 200. A question about a date reads the commit of the latest point on or before it. Use it when the commits stand for other dates than the days they were written (a demo's milestones, an import of old records); without it the server reads the last commit written by the end of that day. | |
| embedding | No | One embedding by name (see lbb_embeddings action=list). Omit it to search every searchable class of the graph; each hit names its class. | |
| row_limit | No | Maximum query rows to return in this page. Defaults by detail: compact=20, standard=100, full=1000. | |
| entailment | No | Reasoning over the pinned RDF generation. Defaults to none. owl includes RDFS, inverse relationships and the supported OWL profile. | |
| consistency | No | Read consistency. strong requires publication through head; a pending response is retryable. | |
| min_indexed_seq | No | Read-after-write publication floor. Preserved across cursor pages. | |
| as_of_commit_seq | No | Snapshot pin: evaluate the body as of this commit_seq, hiding later commits. Errors if past head. Top-level alias for the body's `as_of_commit_seq` (either works for this one). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With only readOnlyHint available in annotations, the description carries real behavioral burden and delivers: questions consume model tokens and count toward a daily limit, structured/text queries pin one watermark, strong consistency requires publication through head and a pending response is retryable, errors if past head, CONSTRUCT/DESCRIBE and combinators are rejected, uppercase IRIs are auto-lowercased with a notes entry, and rerank adds ~0.3s. This is unusually rich disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the mode list and the highest-value routing rule (mode=question) before descending into detail, so the critical information is not buried. It is dense and long with some tangential depth (multiple full examples, rerank mechanics), but most sentences earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 32-parameter, nested-object tool with no output schema, the description is close to complete: it explains return shape of question mode (route, rationale, query, rows) and points to the result's search field for the plan. Minor gaps remain around pagination/cursor behavior, but overall it equips an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 84%, so the schema already documents most parameters, including the elaborate body shape. The description adds mode-selection meaning and a couple of worked patterns, but for individual parameters it largely restates what the schema provides, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (reads) and resource (the graph) and enumerates the five modes with a one-line gloss of each, so an agent knows this is the analytical/expert query surface. It names siblings (lbb_inspect, lbb_embeddings, lbb_evals) as supporting steps, though it does not sharply draw the boundary against them for tool selection.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use routing: 'Use mode=question when you have a question in plain words and no SPARQL query,' 'Continue or correct that query with mode=sparql,' and the SPARQL-vs-search distinction ('SPARQL is the query language; search finds what the words describe'). It also lays out a planning workflow (explain=true, lbb_embeddings action=list). It stops short of explicit when-not-to-use guidance against siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lbb_rdfADestructiveIdempotent
Store and extend complete RDF/OWL documents through MCP. import accepts Turtle/N-Triples/N-Quads/TriG without conversion; update executes INSERT DATA for additive edits. Replacing/removing axioms is unsupported; use a new versioned LBB graph for a revised document. Named RDF graphs are unsupported; Turtle/N-Triples use the default graph, and dataset formats must contain only default-graph quads. These write graph facts, distinct from lbb_configure's native schema metadata. A first RDF write selects RDF-native storage, which refuses later property-graph commits; choose the write workflow before bootstrap. Retries deduplicate by content unless idempotency_key is supplied. A completed write schedules publication; inspect action=publication and verify using lbb_query entailment=owl.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Graph to target; defaults to the connection's graph | |
| action | Yes | Selects the variant (one of: import, update). | |
| detail | No | Response detail level. Defaults to compact. | |
| format | No | ||
| source | No | Complete RDF document. Preserves OWL axioms, RDF lists, labels, comments, and external IRIs as graph facts. | |
| update | No | SPARQL INSERT DATA text to add axioms. Submitted unchanged. DELETE/WHERE/CLEAR and named graphs are currently unsupported and fail without mutation. | |
| base_iri | No | ||
| idempotency_key | No | ||
| blank_node_scope | No | Stable document scope for blank labels across import chunks. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavioral context beyond the annotations: import accepts formats without conversion, update is additive INSERT DATA, the first RDF write locks storage mode and refuses later property-graph commits, retries deduplicate by content unless idempotency_key is supplied, and completed writes schedule publication. These details align with the write-oriented annotations and explain important side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is dense but every sentence carries an operational constraint or decision point. It is front-loaded with the core purpose, then efficiently covers formats, unsupported operations, storage implications, retry behavior, and publication without filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex write tool with nine parameters and no output schema, the description covers most critical context: supported actions, formats, unsupported operations, storage-mode consequences, retries, and post-write publication/verification. The remaining gap is the lack of guidance on base_iri and the meaning of detail levels, so it is not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema descriptions already cover several parameters, and the description adds meaning for format by listing accepted RDF formats and the default-graph restriction, and for idempotency_key by explaining content-deduplication behavior. However, base_iri remains undocumented in both the schema and description, so parameter semantics are strong but not complete.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific action: store and extend complete RDF/OWL documents via MCP, with the two variants import and update acting on RDF graph facts. It also distinguishes the tool from sibling lbb_configure, which handles native schema metadata, so an agent can tell them apart.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use and when-not-to-use guidance: replacing/removing axioms is unsupported and should instead use a new versioned LBB graph; named RDF graphs are unsupported; and verification should use lbb_query entailment=owl. This clearly routes an agent away from misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.9.0- Changed
lbb_configure5 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change)."New value: +"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change, get_rewrite_profile, set_rewrite_profile)." - changed
Input schema / properties / action / enumPrevious value: -[ - "define_ontology", - "publish_schema", - "evolve_ontology", - "list_starters", - "apply_starter", - "suggest_ontology_change" -]New value: +[ + "define_ontology", + "publish_schema", + "evolve_ontology", + "list_starters", + "apply_starter", + "suggest_ontology_change", + "get_rewrite_profile", + "set_rewrite_profile" +] - added
Input schema / properties / examplesAdded value: +{ + "description": "Up to 20 worked examples: a question and the query that answers it on this graph", + "items": { + "additionalProperties": false, + "properties": { + "note": { + "maxLength": 1000, + "type": "string" + }, + "question": { + "maxLength": 1000, + "minLength": 1, + "type": "string" + }, + "sparql": { + "description": "A SELECT or ASK query with its PREFIX lines; the server parses it", + "maxLength": 4000, + "minLength": 1, + "type": "string" + } + }, + "required": [ + "question", + "sparql" + ], + "type": "object" + }, + "maxItems": 20, + "type": "array" +} - added
Input schema / properties / expected_versionAdded value: +{ + "description": "The version get_rewrite_profile returned (0 for none): another stored version answers 409 conflict and stores nothing", + "minimum": 0, + "type": "integer" +} - added
Input schema / properties / notesAdded value: +{ + "description": "What the data means for questions: which property holds the current state, what 'me' or 'my' means, which records to leave out. At most 8,000 characters", + "maxLength": 8000, + "type": "string" +}
- Changed
lbb_evals11 fields changed- changed
Input schema / properties / action / enumPrevious value: -[ - "summary", - "traces", - "trace", - "label", - "judge", - "goldens", - "golden", - "accept", - "delete", - "run", - "results", - "settings" -]New value: +[ + "summary", + "traces", + "trace", + "label", + "judge", + "goldens", + "golden", + "accept", + "delete", + "run", + "results", + "settings", + "checks_summary", + "checks", + "review_check" +] - added
Input schema / properties / afterAdded value: +{ + "description": "checks: the next_after of the previous page.", + "type": "string" +} - added
Input schema / properties / agreeAdded value: +{ + "description": "review_check: true = the judge is right, false = correct it with verdict.", + "type": "boolean" +} - added
Input schema / properties / call_idAdded value: +{ + "description": "review_check: the check's `call` id, from checks.", + "type": "string" +} - added
Input schema / properties / jobAdded value: +{ + "description": "checks: only the checks of one job.", + "enum": [ + "rerank", + "route", + "rewrite", + "fit", + "propose", + "label" + ], + "type": "string" +} - added
Input schema / properties / monthAdded value: +{ + "description": "checks_summary / checks: the month, yyyy-mm (UTC). Defaults to the current month.", + "pattern": "^\\d{4}-(0[1-9]|1[0-2])$", + "type": "string" +} - added
Input schema / properties / note / descriptionAdded value: +"label / review_check: why. review_check: at most 2,000 characters." - added
Input schema / properties / referenceAdded value: +{ + "additionalProperties": {}, + "description": "review_check with agree=false: the right answer. A rerank or label check: {\"grades\": {\"<hit id>\": 0..3}}; a route or fit check: {\"picks\": {\"<question id>\": \"<option>\"}}.", + "type": "object" +} - added
Input schema / properties / reviewedAdded value: +{ + "description": "checks: true = only the checks a person reviewed, false = only the others.", + "type": "boolean" +} - added
Input schema / properties / scoreAdded value: +{ + "description": "review_check with agree=false: the right score, 0 to 1. Omit for the judge's score of that verdict.", + "maximum": 1, + "minimum": 0, + "type": "number" +} - added
Input schema / properties / verdictAdded value: +{ + "description": "checks: only the checks whose ground truth has this verdict. review_check with agree=false: the right verdict.", + "enum": [ + "right", + "partly", + "wrong" + ], + "type": "string" +}
- Changed
lbb_inspect1 field changed- changed
Input schema / properties / as_of / descriptionPrevious value: -"Valid-time snapshot pin (RFC3339): reproduce the node as of this instant."New value: +"Unsupported for entity; use as_of_commit_seq for a retained commit snapshot."
- Changed
lbb_models2 fields changed- changed
Input schema / properties / action / enumPrevious value: -[ - "shadow_eval", - "suggest_dataset", - "extractor_dataset" -]New value: +[ + "shadow_eval", + "suggest_dataset", + "extractor_dataset", + "activity" +] - added
Input schema / properties / monthAdded value: +{ + "description": "activity: the month, yyyy-mm (UTC). Defaults to the current month.", + "pattern": "^\\d{4}-(0[1-9]|1[0-2])$", + "type": "string" +}
- Changed
lbb_query11 fields changed- added
Input schema / properties / anchorAdded value: +{ + "description": "question: entity IRIs the question is about, at most 10 (for example the record the user has open). The server reads each one, and the query uses these IRIs directly instead of matching their names.", + "items": { + "maxLength": 2000, + "minLength": 1, + "type": "string" + }, + "maxItems": 10, + "type": "array" +} - added
Input schema / properties / contextAdded value: +{ + "description": "question: notes for the model, at most 8,000 characters: what the data means, units, names to prefer.", + "type": "string" +} - added
Input schema / properties / limitAdded value: +{ + "description": "question: rows the run returns, 1 to 1,000. Defaults by detail: compact=20, standard=100, full=1000.", + "maximum": 1000, + "minimum": 1, + "type": "integer" +} - changed
Input schema / properties / mode / descriptionPrevious value: -"Selects the variant (one of: structured, sparql, search, analyze)."New value: +"Selects the variant (one of: structured, sparql, question, search, analyze)." - changed
Input schema / properties / mode / enumPrevious value: -[ - "structured", - "sparql", - "search", - "analyze" -]New value: +[ + "structured", + "sparql", + "question", + "search", + "analyze" +] - changed
Input schema / properties / query / descriptionPrevious value: -"SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10"New value: +"SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10. Search by meaning inside the query (the graph needs an embedding; see lbb_embeddings action=list): PREFIX search: <https://littlebigbrain.com/search#> SELECT ?x ?score WHERE { ?x search:similarTo \"card payments\" ; search:score ?score . ?x <https://littlebigbrain.com/r/calls> ?y } ORDER BY DESC(?score) LIMIT 5. The other patterns filter and join the hits. One search:similarTo per query, with a variable subject, in the main group (not inside OPTIONAL, UNION, MINUS or a subquery). The object is text, an entity IRI (records like that one) or a vector literal. search:top N sets the hits (1 to 1000; default the query LIMIT, then 10) and search:embedding \"name\" searches one embedding. FILTER(?score > 0.8) keeps close hits. The result's search field reports the plan (nearest, filter_first or search_first), the hits and complete. For a question in words, add search:rerank true ; search:relevance ?r and ORDER BY DESC(?r): the rerank model (Jev) reads the best hits with the text, keeps the top that answer it and binds its answer (0 to 1); search.rerank reports the status. Only a text query reranks." - added
Input schema / properties / questionAdded value: +{ + "description": "question: the question in plain words (required), 1 to 4,000 characters. The server writes the SPARQL query from a description of this graph, checks it, and runs it.", + "minLength": 1, + "type": "string" +} - added
Input schema / properties / rerankAdded value: +{ + "description": "true: the managed rerank model (Jev) orders the best hits by how well each answers the text, and each hit gets its relevance (0 to 1); adds about 0.3 s. false: the similarity order. Omit it to follow the graph's search setting.", + "type": "boolean" +} - added
Input schema / properties / routeAdded value: +{ + "description": "question: the kind of query, when you know it. Omit it and the router model selects it.", + "enum": [ + "lookup", + "aggregate", + "search", + "history", + "schema", + "unanswerable" + ], + "type": "string" +} - added
Input schema / properties / runAdded value: +{ + "description": "question: run the query and return its rows. Defaults to true; false returns the query only.", + "type": "boolean" +} - added
Input schema / properties / timelineAdded value: +{ + "description": "question: dated points that stand for the graph's commits, at most 200. A question about a date reads the commit of the latest point on or before it. Use it when the commits stand for other dates than the days they were written (a demo's milestones, an import of old records); without it the server reads the last commit written by the end of that day.", + "items": { + "additionalProperties": false, + "properties": { + "as_of_commit_seq": { + "description": "The commit that holds the graph as it was on that date.", + "minimum": 0, + "type": "integer" + }, + "date": { + "description": "YYYY-MM-DD.", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$", + "type": "string" + }, + "label": { + "description": "A name for the point, such as a milestone.", + "maxLength": 200, + "type": "string" + } + }, + "required": [ + "date", + "as_of_commit_seq" + ], + "type": "object" + }, + "maxItems": 200, + "type": "array" +}
2 tool updates
v0.8.1- Changed
lbb_configure11 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology)."New value: +"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change)." - changed
Input schema / properties / action / enumPrevious value: -[ - "define_ontology", - "publish_schema", - "evolve_ontology" -]New value: +[ + "define_ontology", + "publish_schema", + "evolve_ontology", + "list_starters", + "apply_starter", + "suggest_ontology_change" +] - added
Input schema / properties / agentAdded value: +{ + "description": "Your name as the producer, shown to reviewers", + "maxLength": 200, + "type": "string" +} - added
Input schema / properties / anchorAdded value: +{ + "additionalProperties": false, + "description": "The class, property or relation the change is about", + "properties": { + "kind": { + "enum": [ + "ontology", + "class", + "property", + "relation" + ], + "type": "string" + }, + "name": { + "maxLength": 200, + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" +} - added
Input schema / properties / changeAdded value: +{ + "description": "The ontology operations a person applies by accepting, in order (same shapes as evolve_ontology ops)", + "items": { + "$ref": "#/properties/ops/items" + }, + "maxItems": 128, + "minItems": 1, + "type": "array" +} - added
Input schema / properties / evidenceAdded value: +{ + "additionalProperties": false, + "description": "What you saw: record count, fields, up to 20 sample records", + "properties": { + "records": { + "minimum": 0, + "type": "integer" + }, + "samples": { + "items": { + "$ref": "#/properties/entity_types/items/anyOf/1" + }, + "maxItems": 20, + "type": "array" + }, + "source_fields": { + "items": { + "type": "string" + }, + "maxItems": 200, + "type": "array" + } + }, + "type": "object" +} - added
Input schema / properties / expected_ontology_versionAdded value: +{ + "description": "Refuse when the graph's ontology version differs", + "minimum": 0, + "type": "integer" +} - added
Input schema / properties / keyAdded value: +{ + "description": "Idempotency key ([A-Za-z0-9-_.:/]); filing again with the same key revises the suggestion", + "maxLength": 255, + "type": "string" +} - added
Input schema / properties / rationaleAdded value: +{ + "description": "Why the ontology needs the change; cite what you saw", + "maxLength": 4000, + "type": "string" +} - added
Input schema / properties / starterAdded value: +{ + "description": "Starter id: crm, documents or work (list_starters names them)", + "minLength": 1, + "type": "string" +} - added
Input schema / properties / titleAdded value: +{ + "description": "Short imperative text, e.g. 'Add class Contractor'", + "maxLength": 200, + "minLength": 1, + "type": "string" +}
- Changed
lbb_inspect4 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, entity)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, ontology_suggestions, entity)." - changed
Input schema / properties / action / enumPrevious value: -[ - "guide", - "ontology", - "ontology_conformance", - "schema", - "graphs", - "publication", - "ontology_search", - "metadata", - "entity" -]New value: +[ + "guide", + "ontology", + "ontology_conformance", + "schema", + "graphs", + "publication", + "ontology_search", + "metadata", + "ontology_suggestions", + "entity" +] - added
Input schema / properties / limitAdded value: +{ + "maximum": 500, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / statusAdded value: +{ + "description": "Only suggestions in this state; default all", + "enum": [ + "open", + "accepted", + "dismissed", + "superseded" + ], + "type": "string" +}
2 tool updates
v0.6.0- Changed
lbb_inspect8 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, entity, state, history, why, transitions)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, entity)." - changed
Input schema / properties / action / enumPrevious value: -[ - "guide", - "ontology", - "ontology_conformance", - "schema", - "graphs", - "publication", - "ontology_search", - "metadata", - "entity", - "state", - "history", - "why", - "transitions" -]New value: +[ + "guide", + "ontology", + "ontology_conformance", + "schema", + "graphs", + "publication", + "ontology_search", + "metadata", + "entity" +] - changed
Input schema / properties / as_of_commit_seq / descriptionPrevious value: -"Snapshot pin: reproduce the node (state, edges, history) as of this commit_seq."New value: +"Snapshot pin: reproduce the node's attributes and relationships as of this commit_seq." - removed
Input schema / properties / relationRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / source_nameRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / source_typeRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / target_nameRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / target_typeRemoved value: -{ - "type": "string" -}
- Changed
lbb_models1 field changed- changed
Input schema / properties / action / enumPrevious value: -[ - "shadow_eval", - "planner_dataset", - "planner_preference_dataset", - "suggest_dataset", - "extractor_dataset" -]New value: +[ + "shadow_eval", + "suggest_dataset", + "extractor_dataset" +]
12 tool updates
v0.5.2- Removed
lbb_branch - Changed
lbb_commit1 field changed- removed
Input schema / properties / branchRemoved value: -{ - "description": "Branch to target; defaults to the connection's branch", - "type": "string" -}
- Changed
lbb_configure1 field changed- removed
Input schema / properties / branchRemoved value: -{ - "description": "Branch to target; defaults to the connection's branch", - "type": "string" -}
- Added
lbb_embeddings - Added
lbb_embeddings_delete - Added
lbb_embeddings_manage - Added
lbb_evals - Changed
lbb_inspect1 field changed- removed
Input schema / properties / branchRemoved value: -{ - "description": "Branch to target; defaults to the connection's branch", - "type": "string" -}
- Changed
lbb_models1 field changed- removed
Input schema / properties / branchRemoved value: -{ - "description": "Branch to target; defaults to the connection's branch", - "type": "string" -}
- Removed
lbb_observe - Changed
lbb_query11 fields changed- removed
Input schema / properties / branchRemoved value: -{ - "description": "Branch to target; defaults to the connection's branch", - "type": "string" -} - added
Input schema / properties / embeddingAdded value: +{ + "description": "One embedding by name (see lbb_embeddings action=list). Omit it to search every searchable class of the graph; each hit names its class.", + "type": "string" +} - added
Input schema / properties / explainAdded value: +{ + "description": "Plan without running: the scope, the resolved filter, and the allowed count. No model call.", + "type": "boolean" +} - added
Input schema / properties / filterAdded value: +{ + "description": "Conditions every hit must meet: {\"class\": …} or {\"via\": …, \"to\": …}. The response's filter shows how each condition resolved; an unknown relationship or name answers with the options.", + "items": { + "additionalProperties": false, + "properties": { + "class": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "A class condition: one class IRI or a list (any of); subclasses too. One class condition per search." + }, + "direction": { + "description": "With via: out (default), the hit links to the entity; in, the entity links to the hit.", + "enum": [ + "out", + "in" + ], + "type": "string" + }, + "to": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ], + "description": "With via: the entity, an IRI or a name (its label; a spelling slip resolves when one entity is clearly closest), or a list (any of)." + }, + "via": { + "description": "A relationship condition: the relationship, a local name (calls), prefix:name, or <iri>.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" +} - added
Input schema / properties / includeAdded value: +{ + "description": "text: return the embedded text of each hit.", + "items": { + "enum": [ + "text" + ], + "type": "string" + }, + "type": "array" +} - changed
Input schema / properties / mode / descriptionPrevious value: -"Selects the variant (one of: structured, sparql, analyze)."New value: +"Selects the variant (one of: structured, sparql, search, analyze)." - changed
Input schema / properties / mode / enumPrevious value: -[ - "structured", - "sparql", - "analyze" -]New value: +[ + "structured", + "sparql", + "search", + "analyze" +] - added
Input schema / properties / probeAdded value: +{ + "description": "Clusters to read (default 4·√clusters, at least 8). More reads cost latency and find more.", + "exclusiveMinimum": 0, + "type": "integer" +} - added
Input schema / properties / requestAdded value: +{ + "description": "The user's own words behind this query (managed evals). When present the server records an eval trace and the result carries its trace_id; label the rows valid or not with lbb_evals action=label. Omit on continuation pages.", + "type": "string" +} - added
Input schema / properties / textAdded value: +{ + "description": "The query text (required); embedded with the graph's model.", + "type": "string" +} - added
Input schema / properties / top_k / maximumAdded value: +200
- Changed
lbb_rdf1 field changed- removed
Input schema / properties / branchRemoved value: -{ - "description": "Branch to target; defaults to the connection's branch", - "type": "string" -}
5 tool updates
v0.5.1- Changed
lbb_commit1 field changed- added
Input schema / properties / dry_runAdded value: +{ + "description": "Validate a facts commit and return its structured SHACL report without writing. Only supported for mode=facts.", + "type": "boolean" +}
- Changed
lbb_configure9 fields changed- changed
Input schema / properties / allow_data_conflicts / descriptionPrevious value: -"Apply subtractive ops (narrow/remove) even when current data conflicts; affected records are kept and begin to warn. Default false rejects a conflicting subtractive request and reports the conflicts."New value: +"Deprecated compatibility flag; does not bypass conflicts. Preview subtractive changes with dry_run=true, repair the reported conflicts, then apply." - added
Input schema / properties / dry_runAdded value: +{ + "description": "Preview the exact definition without creating a graph or writing metadata.", + "type": "boolean" +} - removed
Input schema / properties / entity_types / items / additionalPropertiesRemoved value: -{} - added
Input schema / properties / entity_types / items / anyOfAdded value: +[ + { + "type": "string" + }, + { + "additionalProperties": {}, + "type": "object" + } +] - removed
Input schema / properties / entity_types / items / typeRemoved value: -"object" - changed
Input schema / properties / ops / items / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "add_domain": { - "description": "Entity-type names to add to the relation's domain (source types)", - "items": { - "type": "string" - }, - "type": "array" - }, - "add_range": { - "description": "Entity-type names to add to the relation's range (target types)", - "items": { - "type": "string" - }, - "type": "array" - }, - "op": { - "const": "widen_relation", - "type": "string" - }, - "relation": { - "description": "Relation to widen, by name (case-insensitive)", - "type": "string" - } - }, - "required": [ - "op", - "relation" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "name": { - "description": "Display name of the new entity type (idempotent if it exists)", - "type": "string" - }, - "op": { - "const": "add_entity_type", - "type": "string" - } - }, - "required": [ - "op", - "name" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "cardinality": { - "description": "Defaults to many_to_many", - "enum": [ - "one_to_one", - "one_to_many", - "many_to_one", - "many_to_many" - ], - "type": "string" - }, - "domain": { - "description": "Entity-type names allowed as the source (domain); must already exist", - "items": { - "type": "string" - }, - "type": "array" - }, - "inverse_name": { - "description": "Optional inverse-relation display name, e.g. PHASE_OF (enables one-hop reverse traversal)", - "type": "string" - }, - "name": { - "description": "Display name of the new relation, e.g. HAS_PHASE", - "type": "string" - }, - "op": { - "const": "add_relation", - "type": "string" - }, - "range": { - "description": "Entity-type names allowed as the target (range); must already exist", - "items": { - "type": "string" - }, - "type": "array" - }, - "reducer": { - "description": "State-reducer token, e.g. append_only (default), latest_wins", - "type": "string" - }, - "symmetric": { - "type": "boolean" - }, - "temporal_semantics": { - "description": "Defaults to bitemporal", - "enum": [ - "atemporal", - "valid_time", - "commit_time", - "bitemporal" - ], - "type": "string" - }, - "transitive": { - "type": "boolean" - } - }, - "required": [ - "op", - "name" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "name": { - "description": "Display name of the new scalar property field, e.g. status (idempotent if it exists)", - "type": "string" - }, - "op": { - "const": "add_property", - "type": "string" - }, - "required": { - "description": "Advisory required flag (not enforced on commit)", - "type": "boolean" - }, - "value_type": { - "description": "Scalar type; defaults to text. Lets a later lbb_commit set entity_properties[].field", - "enum": [ - "bool", - "i64", - "f64", - "date_time", - "keyword", - "text", - "bytes" - ], - "type": "string" - } - }, - "required": [ - "op", - "name" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "from": { - "description": "Current entity-type name", - "type": "string" - }, - "op": { - "const": "rename_entity_type", - "type": "string" - }, - "to": { - "description": "New display name (stable id stays frozen; records keep resolving)", - "type": "string" - } - }, - "required": [ - "op", - "from", - "to" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "from": { - "description": "Current relation name", - "type": "string" - }, - "op": { - "const": "rename_relation", - "type": "string" - }, - "to": { - "description": "New display name (stable id stays frozen; edges keep resolving)", - "type": "string" - } - }, - "required": [ - "op", - "from", - "to" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "inverse_name": { - "description": "Inverse-relation display name, e.g. PHASE_OF (enables one-hop reverse traversal)", - "type": "string" - }, - "op": { - "const": "set_relation_inverse", - "type": "string" - }, - "relation": { - "description": "Relation to set the inverse on, by name", - "type": "string" - } - }, - "required": [ - "op", - "relation", - "inverse_name" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "cardinality": { - "enum": [ - "one_to_one", - "one_to_many", - "many_to_one", - "many_to_many" - ], - "type": "string" - }, - "op": { - "const": "set_relation_cardinality", - "type": "string" - }, - "relation": { - "description": "Relation to change, by name", - "type": "string" - } - }, - "required": [ - "op", - "relation", - "cardinality" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "op": { - "const": "narrow_relation", - "type": "string" - }, - "relation": { - "description": "Relation to narrow, by name", - "type": "string" - }, - "remove_domain": { - "description": "Entity-type names to remove from the relation's domain (subtractive)", - "items": { - "type": "string" - }, - "type": "array" - }, - "remove_range": { - "description": "Entity-type names to remove from the relation's range (subtractive)", - "items": { - "type": "string" - }, - "type": "array" - } - }, - "required": [ - "op", - "relation" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "name": { - "description": "Entity type to tombstone — kept readable for old records, rejected for new commits", - "type": "string" - }, - "op": { - "const": "remove_entity_type", - "type": "string" - } - }, - "required": [ - "op", - "name" - ], - "type": "object" - }, - { - "additionalProperties": false, - "properties": { - "name": { - "description": "Relation to tombstone — old edges stay readable, rejected for new commits", - "type": "string" - }, - "op": { - "const": "remove_relation", - "type": "string" - } - }, - "required": [ - "op", - "name" - ], - "type": "object" - } -]New value: +[ + { + "additionalProperties": false, + "properties": { + "entity_type": { + "type": "string" + }, + "op": { + "const": "add_super_types", + "type": "string" + }, + "super_types": { + "items": { + "type": "string" + }, + "minItems": 1, + "type": "array" + } + }, + "required": [ + "op", + "entity_type", + "super_types" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "add_domain": { + "description": "Entity-type names to add to the relation's domain (source types)", + "items": { + "type": "string" + }, + "type": "array" + }, + "add_range": { + "description": "Entity-type names to add to the relation's range (target types)", + "items": { + "type": "string" + }, + "type": "array" + }, + "op": { + "const": "widen_relation", + "type": "string" + }, + "relation": { + "description": "Relation to widen, by name (case-insensitive)", + "type": "string" + } + }, + "required": [ + "op", + "relation" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "name": { + "description": "Display name of the new entity type (idempotent if it exists)", + "type": "string" + }, + "op": { + "const": "add_entity_type", + "type": "string" + } + }, + "required": [ + "op", + "name" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "cardinality": { + "description": "Defaults to many_to_many", + "enum": [ + "one_to_one", + "one_to_many", + "many_to_one", + "many_to_many" + ], + "type": "string" + }, + "domain": { + "description": "Entity-type names allowed as the source (domain); must already exist", + "items": { + "type": "string" + }, + "type": "array" + }, + "inverse_name": { + "description": "Optional inverse-relation display name, e.g. PHASE_OF (enables one-hop reverse traversal)", + "type": "string" + }, + "name": { + "description": "Display name of the new relation, e.g. HAS_PHASE", + "type": "string" + }, + "op": { + "const": "add_relation", + "type": "string" + }, + "range": { + "description": "Entity-type names allowed as the target (range); must already exist", + "items": { + "type": "string" + }, + "type": "array" + }, + "reducer": { + "description": "State-reducer token, e.g. append_only (default), latest_wins", + "type": "string" + }, + "symmetric": { + "type": "boolean" + }, + "temporal_semantics": { + "description": "Defaults to bitemporal", + "enum": [ + "atemporal", + "valid_time", + "commit_time", + "bitemporal" + ], + "type": "string" + }, + "transitive": { + "type": "boolean" + } + }, + "required": [ + "op", + "name" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "name": { + "description": "Display name of the new scalar property field, e.g. status (idempotent if it exists)", + "type": "string" + }, + "op": { + "const": "add_property", + "type": "string" + }, + "required": { + "description": "Advisory required flag (not enforced on commit)", + "type": "boolean" + }, + "value_type": { + "description": "Scalar type; defaults to text. Lets a later lbb_commit set entity_properties[].field", + "enum": [ + "bool", + "i64", + "f64", + "date_time", + "keyword", + "text", + "bytes" + ], + "type": "string" + } + }, + "required": [ + "op", + "name" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "from": { + "description": "Current entity-type name", + "type": "string" + }, + "op": { + "const": "rename_entity_type", + "type": "string" + }, + "to": { + "description": "New display name (stable id stays frozen; records keep resolving)", + "type": "string" + } + }, + "required": [ + "op", + "from", + "to" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "from": { + "description": "Current relation name", + "type": "string" + }, + "op": { + "const": "rename_relation", + "type": "string" + }, + "to": { + "description": "New display name (stable id stays frozen; edges keep resolving)", + "type": "string" + } + }, + "required": [ + "op", + "from", + "to" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "inverse_name": { + "description": "Inverse-relation display name, e.g. PHASE_OF (enables one-hop reverse traversal)", + "type": "string" + }, + "op": { + "const": "set_relation_inverse", + "type": "string" + }, + "relation": { + "description": "Relation to set the inverse on, by name", + "type": "string" + } + }, + "required": [ + "op", + "relation", + "inverse_name" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "cardinality": { + "enum": [ + "one_to_one", + "one_to_many", + "many_to_one", + "many_to_many" + ], + "type": "string" + }, + "op": { + "const": "set_relation_cardinality", + "type": "string" + }, + "relation": { + "description": "Relation to change, by name", + "type": "string" + } + }, + "required": [ + "op", + "relation", + "cardinality" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "op": { + "const": "narrow_relation", + "type": "string" + }, + "relation": { + "description": "Relation to narrow, by name", + "type": "string" + }, + "remove_domain": { + "description": "Entity-type names to remove from the relation's domain (subtractive)", + "items": { + "type": "string" + }, + "type": "array" + }, + "remove_range": { + "description": "Entity-type names to remove from the relation's range (subtractive)", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "op", + "relation" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "name": { + "description": "Entity type to tombstone — kept readable for old records, rejected for new commits", + "type": "string" + }, + "op": { + "const": "remove_entity_type", + "type": "string" + } + }, + "required": [ + "op", + "name" + ], + "type": "object" + }, + { + "additionalProperties": false, + "properties": { + "name": { + "description": "Relation to tombstone — old edges stay readable, rejected for new commits", + "type": "string" + }, + "op": { + "const": "remove_relation", + "type": "string" + } + }, + "required": [ + "op", + "name" + ], + "type": "object" + } +] - removed
Input schema / properties / relations / $refRemoved value: -"#/properties/entity_types" - added
Input schema / properties / relations / itemsAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "$ref": "#/properties/entity_types/items/anyOf/1" + } + ] +} - added
Input schema / properties / relations / typeAdded value: +"array"
- Changed
lbb_inspect5 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, ontology_search, metadata, entity, state, history, why, transitions)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, entity, state, history, why, transitions)." - changed
Input schema / properties / action / enumPrevious value: -[ - "guide", - "ontology", - "ontology_conformance", - "schema", - "ontology_search", - "metadata", - "entity", - "state", - "history", - "why", - "transitions" -]New value: +[ + "guide", + "ontology", + "ontology_conformance", + "schema", + "graphs", + "publication", + "ontology_search", + "metadata", + "entity", + "state", + "history", + "why", + "transitions" +] - added
Input schema / properties / cursorAdded value: +{ + "description": "Opaque lbb_inspect continuation. Repeat action and pass the returned next arguments; rejects changed metadata.", + "type": "string" +} - added
Input schema / properties / page_sizeAdded value: +{ + "description": "Maximum complete metadata entries per page; defaults to 50. Nested fields are never truncated; an oversized single entry returns serialized_json fragments to concatenate and parse.", + "maximum": 500, + "minimum": 1, + "type": "integer" +} - added
Input schema / properties / sectionAdded value: +{ + "description": "Optional top-level array to inspect, e.g. entity_type_defs, relation_defs, property_defs, classes, or relations. Omit to page through all sections.", + "type": "string" +}
- Changed
lbb_query6 fields changed- changed
Input schema / properties / as_of / descriptionPrevious value: -"Snapshot pin (valid-time, RFC3339): evaluate the body as of this instant. Folded into the request's `as_of_valid_time`. Top-level here is the supported spelling — a bare `as_of` inside the body is rejected, since the server silently ignores it."New value: +"Unsupported in structured and SPARQL text modes; use as_of_commit_seq for a retained commit snapshot." - changed
Input schema / properties / body / descriptionPrevious value: -"Structured SPARQL-subset request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: \"x\" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { \"compare\": { \"op\": <op>, \"left\": <term>, \"right\": <term> } } (or { \"and\": [<filter>…] }, { \"or\": [<filter>…] }, { \"not\": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { \"var\": \"x\" }, { \"property\": { \"var\": \"x\", \"field\": \"amount\" } } (a typed scalar attribute), or { \"value\": <typed> } — and <typed> is exactly one wrapper: { \"str\": \"…\" }, { \"i64\": 5 }, { \"f64\": 0.9 }, { \"bool\": true }, { \"date_time\": \"2026-01-01\" } (RFC3339), or { \"entity\": { \"entity_type\": \"T\", \"name\": \"N\" } }. Complete runnable example — deals whose amount ≥ 1000000: { \"patterns\": [{ \"subject\": { \"var\": \"d\" }, \"predicate\": \"for_client\", \"object\": { \"var\": \"c\" } }], \"filters\": [{ \"compare\": { \"op\": \"ge\", \"left\": { \"property\": { \"var\": \"d\", \"field\": \"amount\" } }, \"right\": { \"value\": { \"f64\": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: [\"s\"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { \"patterns\": [{ \"subject\": { \"var\": \"c\" }, \"predicate\": \"committed_to\", \"object\": { \"var\": \"repo\" } }], \"group_keys\": [{ \"date_bucket\": { \"var\": \"c\", \"field\": \"committed_at\", \"granularity\": \"month\", \"as\": \"m\" } }, { \"property\": { \"var\": \"c\", \"field\": \"area\", \"as\": \"area\" } }], \"aggregates\": [{ \"func\": \"count\", \"as\": \"n\" }], \"order_by\": [{ \"var\": \"m\" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { \"compare\": { \"op\": \"gt\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 10 } } } }). A `combinators` key (UNION/OPTIONAL/MINUS/EXISTS) is rejected here; express those with SPARQL text under mode=sparql. Cheap aggregate count: pair an equality having (e.g. { \"compare\": { \"op\": \"eq\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning prefer the top-level `as_of` / `as_of_commit_seq` arguments below; a bare `as_of` key inside the body is rejected (the body's valid-time field is `as_of_valid_time`)."New value: +"Structured SPARQL-subset request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: \"x\" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { \"compare\": { \"op\": <op>, \"left\": <term>, \"right\": <term> } } (or { \"and\": [<filter>…] }, { \"or\": [<filter>…] }, { \"not\": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { \"var\": \"x\" }, { \"property\": { \"var\": \"x\", \"field\": \"amount\" } } (a typed scalar attribute), or { \"value\": <typed> } — and <typed> is exactly one wrapper: { \"str\": \"…\" }, { \"i64\": 5 }, { \"f64\": 0.9 }, { \"bool\": true }, { \"date_time\": \"2026-01-01\" } (RFC3339), or { \"entity\": { \"entity_type\": \"T\", \"name\": \"N\" } }. Complete runnable example — deals whose amount ≥ 1000000: { \"patterns\": [{ \"subject\": { \"var\": \"d\" }, \"predicate\": \"for_client\", \"object\": { \"var\": \"c\" } }], \"filters\": [{ \"compare\": { \"op\": \"ge\", \"left\": { \"property\": { \"var\": \"d\", \"field\": \"amount\" } }, \"right\": { \"value\": { \"f64\": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: [\"s\"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { \"patterns\": [{ \"subject\": { \"var\": \"c\" }, \"predicate\": \"committed_to\", \"object\": { \"var\": \"repo\" } }], \"group_keys\": [{ \"date_bucket\": { \"var\": \"c\", \"field\": \"committed_at\", \"granularity\": \"month\", \"as\": \"m\" } }, { \"property\": { \"var\": \"c\", \"field\": \"area\", \"as\": \"area\" } }], \"aggregates\": [{ \"func\": \"count\", \"as\": \"n\" }], \"order_by\": [{ \"var\": \"m\" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { \"compare\": { \"op\": \"gt\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 10 } } } }). A `combinators` key (UNION/OPTIONAL/MINUS/EXISTS) is rejected here; express those with SPARQL text under mode=sparql. Cheap aggregate count: pair an equality having (e.g. { \"compare\": { \"op\": \"eq\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning use the top-level `as_of_commit_seq` argument or the same body field. Valid-time `as_of` and `as_of_valid_time` selectors are unsupported and rejected before HTTP." - added
Input schema / properties / consistencyAdded value: +{ + "description": "Read consistency. strong requires publication through head; a pending response is retryable.", + "enum": [ + "eventual", + "strong" + ], + "type": "string" +} - added
Input schema / properties / entailmentAdded value: +{ + "description": "Reasoning over the pinned RDF generation. Defaults to none. owl includes RDFS, inverse relationships and the supported OWL profile.", + "enum": [ + "none", + "subclass", + "rdfs", + "owl" + ], + "type": "string" +} - added
Input schema / properties / min_indexed_seqAdded value: +{ + "description": "Read-after-write publication floor. Preserved across cursor pages.", + "maximum": 9007199254740991, + "minimum": -9007199254740991, + "type": "integer" +} - changed
Input schema / properties / query / descriptionPrevious value: -"SPARQL 1.1 query text (SELECT or ASK). IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with rdfs:subClassOf closure on by default. Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10"New value: +"SPARQL 1.1 query text (SELECT or ASK). Valid-time as_of is unsupported; use as_of_commit_seq for a retained commit snapshot. IRI scheme: relations are <https://littlebigbrain.com/r/NAME> (NAME lowercased, e.g. writes_to; reverse a relation with the ^ path operator, no stored inverse triple). Types are <https://littlebigbrain.com/class/NAME> (lowercased), matched as `?x a <…/class/NAME>` with explicit entailment=subclass, rdfs, or owl for inference (default none). Property fields are <https://littlebigbrain.com/p/NAME> (lowercased). The local name is ALWAYS lowercase — an uppercase one (e.g. <…/r/FOR_CLIENT>) is a different, non-existent IRI that silently matches nothing; this tool auto-lowercases the local name of /r/, /class/, and /p/ IRIs for you and adds a `notes` entry when it does, so a stray uppercase still resolves. (Structured mode's `predicate` is case-insensitive on its own.) Entities are content-addressed <https://littlebigbrain.com/e/HASH> — never build an entity IRI from a name; anchor a named entity by its label instead: `?e <http://www.w3.org/2000/01/rdf-schema#label> \"Acme\"`. Discover the exact relation and type names with lbb_inspect action=ontology. SELECT and ASK only (CONSTRUCT/DESCRIBE are rejected). Example: SELECT ?service ?db WHERE { ?service <https://littlebigbrain.com/r/writes_to> ?db } LIMIT 10"
- Added
lbb_rdf
5 tool updates
v0.4.2- Removed
lbb_decode - Removed
lbb_ground - Changed
lbb_inspect5 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, ontology_search, metadata, entity, state, history, why, traverse, transitions)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, ontology_search, metadata, entity, state, history, why, transitions)." - changed
Input schema / properties / action / enumPrevious value: -[ - "guide", - "ontology", - "ontology_conformance", - "schema", - "ontology_search", - "metadata", - "entity", - "state", - "history", - "why", - "traverse", - "transitions" -]New value: +[ + "guide", + "ontology", + "ontology_conformance", + "schema", + "ontology_search", + "metadata", + "entity", + "state", + "history", + "why", + "transitions" +] - removed
Input schema / properties / directionRemoved value: -{ - "enum": [ - "out", - "in", - "both" - ], - "type": "string" -} - removed
Input schema / properties / max_hopsRemoved value: -{ - "exclusiveMinimum": 0, - "maximum": 6, - "type": "integer" -} - removed
Input schema / properties / relationsRemoved value: -{ - "items": { - "type": "string" - }, - "type": "array" -}
- Changed
lbb_query2 fields changed- changed
Input schema / properties / body / descriptionPrevious value: -"Structured SPARQL-subset or analytics request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: \"x\" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { \"compare\": { \"op\": <op>, \"left\": <term>, \"right\": <term> } } (or { \"and\": [<filter>…] }, { \"or\": [<filter>…] }, { \"not\": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { \"var\": \"x\" }, { \"property\": { \"var\": \"x\", \"field\": \"amount\" } } (a typed scalar attribute), or { \"value\": <typed> } — and <typed> is exactly one wrapper: { \"str\": \"…\" }, { \"i64\": 5 }, { \"f64\": 0.9 }, { \"bool\": true }, { \"date_time\": \"2026-01-01\" } (RFC3339), or { \"entity\": { \"entity_type\": \"T\", \"name\": \"N\" } }. Complete runnable example — deals whose amount ≥ 1000000: { \"patterns\": [{ \"subject\": { \"var\": \"d\" }, \"predicate\": \"for_client\", \"object\": { \"var\": \"c\" } }], \"filters\": [{ \"compare\": { \"op\": \"ge\", \"left\": { \"property\": { \"var\": \"d\", \"field\": \"amount\" } }, \"right\": { \"value\": { \"f64\": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: [\"s\"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { \"patterns\": [{ \"subject\": { \"var\": \"c\" }, \"predicate\": \"committed_to\", \"object\": { \"var\": \"repo\" } }], \"group_keys\": [{ \"date_bucket\": { \"var\": \"c\", \"field\": \"committed_at\", \"granularity\": \"month\", \"as\": \"m\" } }, { \"property\": { \"var\": \"c\", \"field\": \"area\", \"as\": \"area\" } }], \"aggregates\": [{ \"func\": \"count\", \"as\": \"n\" }], \"order_by\": [{ \"var\": \"m\" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { \"compare\": { \"op\": \"gt\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 10 } } } }); it is evaluated only on this grouped path, NOT alongside `combinators` (UNION/OPTIONAL/MINUS), which route to the analytics engine. Cheap aggregate count: pair an equality having (e.g. { \"compare\": { \"op\": \"eq\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning prefer the top-level `as_of` / `as_of_commit_seq` arguments below; a bare `as_of` key inside the body is rejected (the body's valid-time field is `as_of_valid_time`)."New value: +"Structured SPARQL-subset request body. Shape: { patterns: [{ subject, predicate, object }], filters?, group_by?, group_keys?, aggregates?, having?, order_by?, select?, limit?, distinct? }. Each pattern term is { var: \"x\" } or a fixed { entity: { entity_type, name } }; `predicate` is a relation name and is case-insensitive here (FOR_CLIENT and for_client both resolve — unlike SPARQL text, which needs the lowercased IRI local name). FILTER — `filters` is a list of conditions, each of exact shape { \"compare\": { \"op\": <op>, \"left\": <term>, \"right\": <term> } } (or { \"and\": [<filter>…] }, { \"or\": [<filter>…] }, { \"not\": <filter> }). `op` is one of eq | ne | lt | le | gt | ge (NOT the symbols =,<,>). Each <term> is exactly one of { \"var\": \"x\" }, { \"property\": { \"var\": \"x\", \"field\": \"amount\" } } (a typed scalar attribute), or { \"value\": <typed> } — and <typed> is exactly one wrapper: { \"str\": \"…\" }, { \"i64\": 5 }, { \"f64\": 0.9 }, { \"bool\": true }, { \"date_time\": \"2026-01-01\" } (RFC3339), or { \"entity\": { \"entity_type\": \"T\", \"name\": \"N\" } }. Complete runnable example — deals whose amount ≥ 1000000: { \"patterns\": [{ \"subject\": { \"var\": \"d\" }, \"predicate\": \"for_client\", \"object\": { \"var\": \"c\" } }], \"filters\": [{ \"compare\": { \"op\": \"ge\", \"left\": { \"property\": { \"var\": \"d\", \"field\": \"amount\" } }, \"right\": { \"value\": { \"f64\": 1000000 } } } }] }. Comparisons use the field's real declared type (numbers as numbers, datetimes as instants), so they run server-side. GROUP BY supports both entity-identity keys (group_by: [\"s\"]) and typed scalar keys via group_keys: a property value ({ property: { var, field, as } }) or a calendar bucket of a datetime property ({ date_bucket: { var, field, granularity: year|month|week|day|hour, as } }). Scalar keys come back per group under value_keys[as] — so a per-area breakdown or a commits-per-month time series is one server-side query, no client-side bucketing. Worked example -- commits per area per month in one query: { \"patterns\": [{ \"subject\": { \"var\": \"c\" }, \"predicate\": \"committed_to\", \"object\": { \"var\": \"repo\" } }], \"group_keys\": [{ \"date_bucket\": { \"var\": \"c\", \"field\": \"committed_at\", \"granularity\": \"month\", \"as\": \"m\" } }, { \"property\": { \"var\": \"c\", \"field\": \"area\", \"as\": \"area\" } }], \"aggregates\": [{ \"func\": \"count\", \"as\": \"n\" }], \"order_by\": [{ \"var\": \"m\" }] } -- area and committed_at are typed entity attributes (set via entity_properties; readable flat under attributes, never a nested metadata blob), and each group returns value_keys.m + value_keys.area + aggregates.n. `having: [...]` takes the same filter shape over the aggregated groups (e.g. { \"compare\": { \"op\": \"gt\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 10 } } } }). A `combinators` key (UNION/OPTIONAL/MINUS/EXISTS) is rejected here; express those with SPARQL text under mode=sparql. Cheap aggregate count: pair an equality having (e.g. { \"compare\": { \"op\": \"eq\", \"left\": { \"var\": \"n\" }, \"right\": { \"value\": { \"i64\": 4 } } } }) with row_limit: 1 -- the response row_page.total reports how many groups match without materializing them all, so you read the count off row_page.total instead of paging every matching row. For snapshot pinning prefer the top-level `as_of` / `as_of_commit_seq` arguments below; a bare `as_of` key inside the body is rejected (the body's valid-time field is `as_of_valid_time`)." - changed
Input schema / properties / metric / enumPrevious value: -[ - "entity_types", - "relations", - "overview", - "facets", - "sparql" -]New value: +[ + "entity_types", + "relations", + "overview", + "sparql" +]
- Removed
lbb_search
8 tool updates
v0.2.7- Removed
lbb_ask - Changed
lbb_configure6 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Selects the variant (one of: define_ontology, define_rules, publish_schema, evolve_ontology)."New value: +"Selects the variant (one of: define_ontology, publish_schema, evolve_ontology)." - changed
Input schema / properties / action / enumPrevious value: -[ - "define_ontology", - "define_rules", - "publish_schema", - "evolve_ontology" -]New value: +[ + "define_ontology", + "publish_schema", + "evolve_ontology" +] - removed
Input schema / properties / confirm_emptyRemoved value: -{ - "type": "boolean" -} - changed
Input schema / properties / desired_mode / enumPrevious value: -[ - "warn", - "reject" -]New value: +[ + "off", + "warn", + "reject" +] - removed
Input schema / properties / preview_digestRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / rulesRemoved value: -{ - "items": { - "additionalProperties": true, - "properties": { - "body": { - "description": "The condition: a basic graph pattern over current edges (asserted + already-derived), joined on shared variables. Terms may be variables or fixed entities.", - "items": { - "additionalProperties": true, - "properties": { - "object": { - "$ref": "#/properties/rules/items/properties/body/items/properties/subject", - "description": "A rule term: { \"var\": \"x\" } (a variable) or { \"entity\": { \"entity_type\": \"DeliveryStatus\", \"name\": \"Complete\" } } (a fixed entity used as a constant in the body or head)" - }, - "predicate": { - "description": "Relation name. In a rule body, the reserved \"rdf:type\" makes a type-membership constraint: the object names a class ({ entity: { entity_type: \"Contact\" } }, no name) and matches every entity of that class and its subtypes (rdfs:subClassOf closure), so one rule keyed on a supertype fires for all subtypes. Not allowed in a head or an exists/not_exists filter.", - "type": "string" - }, - "subject": { - "anyOf": [ - { - "additionalProperties": true, - "properties": { - "var": { - "description": "A variable, joined across patterns by name", - "type": "string" - } - }, - "required": [ - "var" - ], - "type": "object" - }, - { - "additionalProperties": true, - "properties": { - "entity": { - "additionalProperties": true, - "properties": { - "entity_id": { - "description": "Entity id (hex), as an alternative to type+name", - "type": "string" - }, - "entity_type": { - "description": "Entity type name (with `name`, names a fixed entity)", - "type": "string" - }, - "name": { - "description": "Entity name (paired with `entity_type`)", - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "entity" - ], - "type": "object" - } - ], - "description": "A rule term: { \"var\": \"x\" } (a variable) or { \"entity\": { \"entity_type\": \"DeliveryStatus\", \"name\": \"Complete\" } } (a fixed entity used as a constant in the body or head)" - } - }, - "type": "object" - }, - "type": "array" - }, - "combinators": { - "description": "exists/not_exists filters folded over the body. not_exists is stratified negation — it lets a rule express a universal condition, e.g. derive \"phase complete\" only when not_exists an incomplete deliverable. A negation cycle is rejected.", - "items": { - "anyOf": [ - { - "additionalProperties": true, - "properties": { - "exists": { - "items": { - "$ref": "#/properties/rules/items/properties/body/items" - }, - "type": "array" - } - }, - "required": [ - "exists" - ], - "type": "object" - }, - { - "additionalProperties": true, - "properties": { - "not_exists": { - "items": { - "$ref": "#/properties/rules/items/properties/body/items" - }, - "type": "array" - } - }, - "required": [ - "not_exists" - ], - "type": "object" - } - ], - "description": "An existence filter over the body solutions: { exists: [...] } (semijoin — keep rows with a compatible match) or { not_exists: [...] } (negation/antijoin — keep rows with none)" - }, - "type": "array" - }, - "head": { - "$ref": "#/properties/rules/items/properties/body/items", - "description": "The triple derived once per body solution. Every head variable must be bound by the body; a fixed-entity object derives a constant (e.g. set the rolled-up status to the Complete entity)." - }, - "name": { - "type": "string" - }, - "order": { - "description": "Run order, low to high (a determinism hint)", - "type": "integer" - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "type": "array" -}
- Changed
lbb_decode5 fields changed- removed
Input schema / properties / source_name / descriptionRemoved value: -"Source entity display name" - removed
Input schema / properties / source_type / descriptionRemoved value: -"Source entity type; omit to have the DB recover it from the name" - removed
Input schema / properties / target_name / descriptionRemoved value: -"Target entity display name" - removed
Input schema / properties / target_type / descriptionRemoved value: -"Target entity type; omit to have the DB recover it from the name" - removed
Input schema / properties / use_model_when_forced / descriptionRemoved value: -"Call the model even when the type pair forces one relation (default false — a forced pair is answered by the DB alone)"
- Changed
lbb_ground5 fields changed- removed
Input schema / properties / action / descriptionRemoved value: -"complete = narrowed vocabulary autocomplete; resolve = snap free text to the nearest real vocabulary; audit = groundability report" - changed
Input schema / properties / kinds / descriptionPrevious value: -"[complete/resolve] Restrict to these vocabulary kinds (default: all)"New value: +"Restrict to these vocabulary kinds (default: all)" - changed
Input schema / properties / sample / descriptionPrevious value: -"[audit] Entities to sample for narrowing-recall"New value: +"[audit] Entities sampled for narrowing recall" - changed
Input schema / properties / text / descriptionPrevious value: -"[resolve] Free text to snap to the nearest real vocabulary item"New value: +"[resolve] Free text to resolve" - changed
Input schema / properties / top_k / descriptionPrevious value: -"[complete/resolve] Max results (default 8)"New value: +"Max results (default 8)"
- Removed
lbb_index - Changed
lbb_inspect12 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Selects the variant (one of: guide, ontology, ontology_conformance, schema, schema_audit, rules, schema_preview, ontology_search, metadata, entity, edges, state, history, why, traverse, transitions)."New value: +"Selects the variant (one of: guide, ontology, ontology_conformance, schema, ontology_search, metadata, entity, state, history, why, traverse, transitions)." - changed
Input schema / properties / action / enumPrevious value: -[ - "guide", - "ontology", - "ontology_conformance", - "schema", - "schema_audit", - "rules", - "schema_preview", - "ontology_search", - "metadata", - "entity", - "edges", - "state", - "history", - "why", - "traverse", - "transitions" -]New value: +[ + "guide", + "ontology", + "ontology_conformance", + "schema", + "ontology_search", + "metadata", + "entity", + "state", + "history", + "why", + "traverse", + "transitions" +] - removed
Input schema / properties / base_ontology_versionRemoved value: -{ - "minimum": 0, - "type": "integer" -} - removed
Input schema / properties / base_shapes_versionRemoved value: -{ - "minimum": 0, - "type": "integer" -} - removed
Input schema / properties / cursorRemoved value: -{ - "description": "Opaque cursor from the previous page's `next_cursor`. The response is the unified list envelope { object:'list', data, has_more, next_cursor, total_count }; page a high-degree node (entity detail hard-caps its edge sample) by feeding next_cursor back here until has_more is false. Each row carries valid_time for a per-edge timeline.", - "type": "string" -} - removed
Input schema / properties / desired_modeRemoved value: -{ - "enum": [ - "warn", - "reject" - ], - "type": "string" -} - removed
Input schema / properties / direction / descriptionRemoved value: -"Edges out of / into / touching the entity (default both)." - removed
Input schema / properties / offsetRemoved value: -{ - "description": "Legacy alias for `cursor` (still accepted); prefer paging with `cursor`.", - "minimum": 0, - "type": "integer" -} - removed
Input schema / properties / ontologyRemoved value: -{ - "additionalProperties": false, - "properties": { - "format": { - "enum": [ - "auto", - "turtle", - "json_ld", - "rdf_xml", - "csv", - "tsv", - "lbb_json", - "spec" - ], - "type": "string" - }, - "source": { - "description": "Ontology source text", - "type": "string" - } - }, - "required": [ - "source" - ], - "type": "object" -} - removed
Input schema / properties / relation / descriptionRemoved value: -"Filter to a single relation name." - removed
Input schema / properties / row_limitRemoved value: -{ - "description": "Max edges returned this page (server caps at 1000; default 150).", - "exclusiveMinimum": 0, - "type": "integer" -} - removed
Input schema / properties / shapesRemoved value: -{ - "additionalProperties": false, - "properties": { - "format": { - "enum": [ - "auto", - "turtle", - "n_triples", - "n_quads", - "trig" - ], - "type": "string" - }, - "source": { - "description": "SHACL/RDF shape source text", - "type": "string" - } - }, - "required": [ - "source" - ], - "type": "object" -}
- Added
lbb_models - Changed
lbb_query16 fields changed- removed
Input schema / properties / anchor_nameRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / anchor_typeRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / explainRemoved value: -{ - "type": "boolean" -} - removed
Input schema / properties / include_derivedRemoved value: -{ - "type": "boolean" -} - removed
Input schema / properties / max_derivedRemoved value: -{ - "exclusiveMinimum": 0, - "type": "integer" -} - removed
Input schema / properties / max_premisesRemoved value: -{ - "exclusiveMinimum": 0, - "type": "integer" -} - removed
Input schema / properties / max_roundsRemoved value: -{ - "exclusiveMinimum": 0, - "type": "integer" -} - removed
Input schema / properties / max_solutionsRemoved value: -{ - "exclusiveMinimum": 0, - "type": "integer" -} - changed
Input schema / properties / mode / descriptionPrevious value: -"Selects the variant (one of: structured, sparql, shacl, infer, retrieval_premises, analyze)."New value: +"Selects the variant (one of: structured, sparql, analyze)." - changed
Input schema / properties / mode / enumPrevious value: -[ - "structured", - "sparql", - "shacl", - "infer", - "retrieval_premises", - "analyze" -]New value: +[ + "structured", + "sparql", + "analyze" +] - removed
Input schema / properties / query_top_kRemoved value: -{ - "exclusiveMinimum": 0, - "type": "integer" -} - removed
Input schema / properties / relationRemoved value: -{ - "type": "string" -} - removed
Input schema / properties / rulesRemoved value: -{ - "items": { - "additionalProperties": true, - "properties": { - "body": { - "description": "The condition: a basic graph pattern over current edges (asserted + already-derived), joined on shared variables. Terms may be variables or fixed entities.", - "items": { - "additionalProperties": true, - "properties": { - "object": { - "$ref": "#/properties/rules/items/properties/body/items/properties/subject", - "description": "A rule term: { \"var\": \"x\" } (a variable) or { \"entity\": { \"entity_type\": \"DeliveryStatus\", \"name\": \"Complete\" } } (a fixed entity used as a constant in the body or head)" - }, - "predicate": { - "description": "Relation name. In a rule body, the reserved \"rdf:type\" makes a type-membership constraint: the object names a class ({ entity: { entity_type: \"Contact\" } }, no name) and matches every entity of that class and its subtypes (rdfs:subClassOf closure), so one rule keyed on a supertype fires for all subtypes. Not allowed in a head or an exists/not_exists filter.", - "type": "string" - }, - "subject": { - "anyOf": [ - { - "additionalProperties": true, - "properties": { - "var": { - "description": "A variable, joined across patterns by name", - "type": "string" - } - }, - "required": [ - "var" - ], - "type": "object" - }, - { - "additionalProperties": true, - "properties": { - "entity": { - "additionalProperties": true, - "properties": { - "entity_id": { - "description": "Entity id (hex), as an alternative to type+name", - "type": "string" - }, - "entity_type": { - "description": "Entity type name (with `name`, names a fixed entity)", - "type": "string" - }, - "name": { - "description": "Entity name (paired with `entity_type`)", - "type": "string" - } - }, - "type": "object" - } - }, - "required": [ - "entity" - ], - "type": "object" - } - ], - "description": "A rule term: { \"var\": \"x\" } (a variable) or { \"entity\": { \"entity_type\": \"DeliveryStatus\", \"name\": \"Complete\" } } (a fixed entity used as a constant in the body or head)" - } - }, - "type": "object" - }, - "type": "array" - }, - "combinators": { - "description": "exists/not_exists filters folded over the body. not_exists is stratified negation — it lets a rule express a universal condition, e.g. derive \"phase complete\" only when not_exists an incomplete deliverable. A negation cycle is rejected.", - "items": { - "anyOf": [ - { - "additionalProperties": true, - "properties": { - "exists": { - "items": { - "$ref": "#/properties/rules/items/properties/body/items" - }, - "type": "array" - } - }, - "required": [ - "exists" - ], - "type": "object" - }, - { - "additionalProperties": true, - "properties": { - "not_exists": { - "items": { - "$ref": "#/properties/rules/items/properties/body/items" - }, - "type": "array" - } - }, - "required": [ - "not_exists" - ], - "type": "object" - } - ], - "description": "An existence filter over the body solutions: { exists: [...] } (semijoin — keep rows with a compatible match) or { not_exists: [...] } (negation/antijoin — keep rows with none)" - }, - "type": "array" - }, - "head": { - "$ref": "#/properties/rules/items/properties/body/items", - "description": "The triple derived once per body solution. Every head variable must be bound by the body; a fixed-entity object derives a constant (e.g. set the rolled-up status to the Complete entity)." - }, - "name": { - "type": "string" - }, - "order": { - "description": "Run order, low to high (a determinism hint)", - "type": "integer" - } - }, - "required": [ - "name" - ], - "type": "object" - }, - "type": "array" -} - removed
Input schema / properties / shacl_modeRemoved value: -{ - "description": "select returns focus nodes; validate returns a report", - "enum": [ - "select", - "validate" - ], - "type": "string" -} - removed
Input schema / properties / shapesRemoved value: -{ - "items": { - "$ref": "#/properties/body" - }, - "type": "array" -} - removed
Input schema / properties / thresholdRemoved value: -{ - "maximum": 1, - "minimum": 0, - "type": "number" -}
11 tool updates
v0.2.1- First observed
lbb_ask - First observed
lbb_branch - First observed
lbb_commit - First observed
lbb_configure - First observed
lbb_decode - First observed
lbb_ground - First observed
lbb_index - First observed
lbb_inspect - First observed
lbb_observe - First observed
lbb_query - First observed
lbb_search
TDQS
Scored across 10 tools
The read tools (lbb_inspect, lbb_query) and the write/schema tools (lbb_commit, lbb_configure, lbb_rdf) have subtly overlapping scopes, but the descriptions explicitly cross-reference each other (e.g. 'Query asserted RDF/OWL axioms separately with lbb_query') to steer selection. The embeddings surface is split across three tools (lbb_embeddings read, lbb_embeddings_manage write, lbb_embeddings_delete), which is defensible but adds boundary checks. Most tools are distinct; only a couple require careful reading.
All tools share a consistent lbb_ prefix and readable noun-oriented names. The only deviation is the noun_verb form of lbb_embeddings_manage and lbb_embeddings_delete versus bare nouns elsewhere, but this is a minor, predictable deviation. No camelCase/snake_case mixing.
Ten tools is well within a reasonable range for a graph/knowledge-base server. However, several tools are large multi-action umbrellas (lbb_inspect lists 10 actions, lbb_query has 5 modes), so the effective surface is heavier than the raw count suggests. Still appropriately scoped.
The surface covers reads, writes, retraction, schema/ontology management, RDF import, embeddings, and eval workflows, which is strong lifecycle coverage. Gaps exist: RDF axiom deletion is explicitly unsupported, and there is no explicit graph create/delete tool despite graphs appearing as a resource. Agents can work around these via versioned graphs.
Maintenance
Related MCP Connectors
MCP server for querying BrainKB, a knowledge base for neuroscience knowledge graphs.
Repository knowledge graph MCP server for codebase understanding and debugging.
MCP server for searching Airweave collections with natural language queries.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP server that enables graph database interactions with Neo4j, allowing users to access and manipulate graph data through natural language commands.-
- AlicenseAqualityDmaintenanceAn MCP server that enables AI-powered exploration of RDF data and SPARQL querying via RDF4J. It provides tools for executing queries, searching knowledge graph resources, and retrieving schema summaries.131MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that builds a knowledge graph from code and text documents, enabling Q\&A and implementation planning via tools like graph_create, graph_plan, and graph_query.7MIT
- FlicenseNot gradedqualityDmaintenanceMCP server that connects AI assistants to the Data Graphs knowledge graph platform, enabling natural language search, exploration, and querying of graph data.6 npm-