Skip to main content
Glama
littlebigbrains

@littlebigbrain/mcp

@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

lbb_inspect

Read the schema, graph status, and entities.

lbb_query

Ask a question in plain words, run SPARQL queries, search by meaning (also inside a SPARQL query with search:similarTo), or request summary statistics. Four modes help an agent write its own queries: names (the IRIs of the names in a text), describe (the classes and properties a question needs, with how many instances hold each property and the values of small classes), commit_at (the commit of a date) and compare (one query at two points, the rows paired by entity).

lbb_rdf

Import RDF documents or add facts with SPARQL INSERT DATA.

lbb_embeddings

Inspect search setup and preview the text to embed.

lbb_embeddings_manage

Set up or refresh embeddings, or change the embedding model.

lbb_embeddings_delete

Delete an embedding and its stored vectors.

lbb_fit_sources

Inspect fit from text and preview the text the fit reads.

lbb_fit_sources_manage

Declare, dry-run or refresh a fit source.

lbb_fit_sources_delete

Delete a fit source; its suggestions stay.

lbb_workflows

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.

lbb_workflows_manage

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.

lbb_workflows_delete

Delete a triggered workflow. What it wrote stays.

lbb_files

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.

lbb_commit

Write or retract JSON facts, or record search feedback.

lbb_configure

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 (get_rewrite_profile, set_rewrite_profile).

lbb_evals

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.

lbb_model_choice

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.

lbb_model_choice_manage

Start or stop a trial, switch a use to a tested model that meets the bar, or revert to LBB's model.

lbb_models

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 test

License

Apache-2.0.

Available Tools

10 tools
lbb_commitA
Idempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNo
graphNoGraph to target; defaults to the connection's graph
dry_runNoValidate a facts commit and return its structured SHACL report without writing. Only supported for mode=facts.
tripletsNo
observed_atNoBackfill 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_edgesNomode=retract: specific edges to remove, matched by (source, relation, target).
idempotency_keyNo
search_feedbackNo
edge_idempotencyNoDefaults to append in MCP. Use skip_unchanged for backfills; it skips exact current-edge duplicates and drops evidence-only repeats.
retract_entitiesNomode=retract: entities whose every current edge is removed (a current-state tombstone; the record and its history are kept for as_of reads).
entity_embeddingsNo
entity_propertiesNoTyped 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

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
keyNoIdempotency key ([A-Za-z0-9-_.:/]); filing again with the same key revises the suggestion
opsNoOntology changes to apply in order (additive, in-place edits, or subtractive)
agentNoYour name as the producer, shown to reviewers
graphNoGraph to create or redefine
notesNoWhat 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
titleNoShort imperative text, e.g. 'Add class Contractor'
actionYesSelects the variant (one of: define_ontology, publish_schema, evolve_ontology, list_starters, apply_starter, suggest_ontology_change, get_rewrite_profile, set_rewrite_profile).
anchorNoThe class, property or relation the change is about
changeNoThe ontology operations a person applies by accepting, in order (same shapes as evolve_ontology ops)
formatNo
shapesNo
sourceNo
dry_runNoPreview the exact definition without creating a graph or writing metadata.
starterNoStarter id: crm, documents or work (list_starters names them)
evidenceNoWhat you saw: record count, fields, up to 20 sample records
examplesNoUp to 20 worked examples: a question and the query that answers it on this graph
ontologyNo
rationaleNoWhy the ontology needs the change; cite what you saw
relationsNo
desired_modeNo
entity_typesNo
merge_defaultNo
expected_versionNoThe version get_rewrite_profile returned (0 for none): another stored version answers 409 conflict and stores nothing
confirm_restrictiveNo
allow_data_conflictsNoDeprecated compatibility flag; does not bypass conflicts. Preview subtractive changes with dry_run=true, repair the reported conflicts, then apply.
expected_ontology_versionNoRefuse when the graph's ontology version differs

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_embeddingsA
Read-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).

ParametersJSON Schema
NameRequiredDescriptionDefault
dimNo
fromNopreview/declare: the fields, e.g. ["label", "description", "calls/label"]. Omit for the automatic choice; on an existing embedding, omit to keep its fields.
irisNopreview: the instances to show instead of a sample.
nameNoget: the embedding name.
classNopreview/declare: the class IRI.
graphNoGraph to target; defaults to the connection's graph
modelNomodel: 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).
titleNopreview/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.
actionYes
detailNoResponse detail level. Defaults to compact.
sampleNo
excludeNopreview/declare: fields to drop from the automatic choice.

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_deleteA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesThe embedding name.
graphNoGraph to target; defaults to the connection's graph
detailNoResponse detail level. Defaults to compact.
confirmYesThe same name again, to confirm.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault
dimNo
fromNopreview/declare: the fields, e.g. ["label", "description", "calls/label"]. Omit for the automatic choice; on an existing embedding, omit to keep its fields.
nameNoThe embedding name (refresh: required).
classNopreview/declare: the class IRI.
graphNoGraph to target; defaults to the connection's graph
modelNomodel: 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).
titleNopreview/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.
actionYes
detailNoResponse detail level. Defaults to compact.
excludeNopreview/declare: fields to drop from the automatic choice.

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
byNolabel: who labels (an agent name).
jobNochecks: only the checks of one job.
itemNolabel: the result id (a hit's `id`, or an item id from trace) to label with `valid`.
noteNolabel / review_check: why. review_check: at most 2,000 characters.
afterNochecks: the next_after of the previous page.
agreeNoreview_check: true = the judge is right, false = correct it with verdict.
graphNoGraph to target; defaults to the connection's graph
itemsNolabel: several results at once.
limitNo
monthNochecks_summary / checks: the month, yyyy-mm (UTC). Defaults to the current month.
scoreNoreview_check with agree=false: the right score, 0 to 1. Omit for the judge's score of that verdict.
top_kNogolden: the top_k of a search golden.
validNolabel: true = the result answers the request (thumbs up), false = it does not.
actionYes
detailNoResponse detail level. Defaults to compact.
sparqlNogolden: the query to freeze (the search text for surface=search).
call_idNoreview_check: the check's `call` id, from checks.
requestNogolden: the user's words the query answers.
surfaceNogolden: which surface the query runs on (default sparql).
verdictNochecks: only the checks whose ground truth has this verdict. review_check with agree=false: the right verdict.
reviewedNochecks: true = only the checks a person reviewed, false = only the others.
trace_idNotrace / label / judge: the trace id from lbb_query.
embeddingNogolden: the embedding, for surface=search.
golden_idNoaccept / delete: the golden id.
referenceNoreview_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>"}}.
unlabeledNotraces: only traces without a label.
consistencyNorun / accept: strong reads the head, eventual the last published commit.

TDQS

A3.7/5.0
Behavior4/5

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.

Conciseness3/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_inspectA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNo
as_ofNoUnsupported for entity; use as_of_commit_seq for a retained commit snapshot.
graphNoGraph to target; defaults to the connection's graph
limitNo
queryNoOntology concept, term, or relation to search
top_kNo
actionYesSelects the variant (one of: guide, ontology, ontology_conformance, schema, graphs, publication, ontology_search, metadata, ontology_suggestions, entity).
cursorNoOpaque lbb_inspect continuation. Repeat action and pass the returned next arguments; rejects changed metadata.
detailNoResponse detail level. Defaults to compact.
statusNoOnly suggestions in this state; default all
sectionNoOptional top-level array to inspect, e.g. entity_type_defs, relation_defs, property_defs, classes, or relations. Omit to page through all sections.
entity_idNoEntity id (hex); alternative to entity_type+name
page_sizeNoMaximum 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_typeNo
as_of_commit_seqNoSnapshot pin: reproduce the node's attributes and relationships as of this commit_seq.

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness3/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_modelsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
bodyNo
graphNoGraph to target; defaults to the connection's graph
limitNo
monthNoactivity: the month, yyyy-mm (UTC). Defaults to the current month.
actionYes
detailNoResponse detail level. Defaults to compact.
split_seqNo

TDQS

A3.5/5.0
Behavior4/5

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.

Conciseness3/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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_queryA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
runNoquestion: run the query and return its rows. Defaults to true; false returns the query only.
bodyNoStructured 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.
modeYesSelects the variant (one of: structured, sparql, question, search, analyze).
textNoThe query text (required); embedded with the graph's model.
as_ofNoUnsupported in structured and SPARQL text modes; use as_of_commit_seq for a retained commit snapshot.
chartNo
fieldNo
graphNoGraph to target; defaults to the connection's graph
limitNoquestion: rows the run returns, 1 to 1,000. Defaults by detail: compact=20, standard=100, full=1000.
probeNoClusters to read (default 4·√clusters, at least 8). More reads cost latency and find more.
queryNoSPARQL 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.
routeNoquestion: the kind of query, when you know it. Omit it and the router model selects it.
top_kNo
anchorNoquestion: 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.
cursorNoOpaque cursor from a previous lbb_query row page; reruns the original query at the next offset.
detailNoResponse detail level. Defaults to compact.
filterNoConditions 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.
metricNo
rerankNotrue: 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.
sparqlNo
contextNoquestion: notes for the model, at most 8,000 characters: what the data means, units, names to prefer.
explainNoPlan without running: the scope, the resolved filter, and the allowed count. No model call.
includeNotext: return the embedded text of each hit.
requestNoThe 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.
questionNoquestion: 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.
timelineNoquestion: 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.
embeddingNoOne embedding by name (see lbb_embeddings action=list). Omit it to search every searchable class of the graph; each hit names its class.
row_limitNoMaximum query rows to return in this page. Defaults by detail: compact=20, standard=100, full=1000.
entailmentNoReasoning over the pinned RDF generation. Defaults to none. owl includes RDFS, inverse relationships and the supported OWL profile.
consistencyNoRead consistency. strong requires publication through head; a pending response is retryable.
min_indexed_seqNoRead-after-write publication floor. Preserved across cursor pages.
as_of_commit_seqNoSnapshot 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

A4.1/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines4/5

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_rdfA
DestructiveIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
graphNoGraph to target; defaults to the connection's graph
actionYesSelects the variant (one of: import, update).
detailNoResponse detail level. Defaults to compact.
formatNo
sourceNoComplete RDF document. Preserves OWL axioms, RDF lists, labels, comments, and external IRIs as graph facts.
updateNoSPARQL INSERT DATA text to add axioms. Submitted unchanged. DELETE/WHERE/CLEAR and named graphs are currently unsupported and fail without mutation.
base_iriNo
idempotency_keyNo
blank_node_scopeNoStable document scope for blank labels across import chunks.

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

  1. 5 tool updatesv0.9.0
    • Changedlbb_configure5 fields changed
      • changedInput schema / properties / action / description
        Previous 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)."
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • addedInput schema / properties / examples
        Added 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"
        +}
      • addedInput schema / properties / expected_version
        Added value: +{
        +  "description": "The version get_rewrite_profile returned (0 for none): another stored version answers 409 conflict and stores nothing",
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / notes
        Added 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"
        +}
    • Changedlbb_evals11 fields changed
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • addedInput schema / properties / after
        Added value: +{
        +  "description": "checks: the next_after of the previous page.",
        +  "type": "string"
        +}
      • addedInput schema / properties / agree
        Added value: +{
        +  "description": "review_check: true = the judge is right, false = correct it with verdict.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / call_id
        Added value: +{
        +  "description": "review_check: the check's `call` id, from checks.",
        +  "type": "string"
        +}
      • addedInput schema / properties / job
        Added value: +{
        +  "description": "checks: only the checks of one job.",
        +  "enum": [
        +    "rerank",
        +    "route",
        +    "rewrite",
        +    "fit",
        +    "propose",
        +    "label"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / month
        Added 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"
        +}
      • addedInput schema / properties / note / description
        Added value: +"label / review_check: why. review_check: at most 2,000 characters."
      • addedInput schema / properties / reference
        Added 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"
        +}
      • addedInput schema / properties / reviewed
        Added value: +{
        +  "description": "checks: true = only the checks a person reviewed, false = only the others.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / score
        Added 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"
        +}
      • addedInput schema / properties / verdict
        Added 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"
        +}
    • Changedlbb_inspect1 field changed
      • changedInput schema / properties / as_of / description
        Previous 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."
    • Changedlbb_models2 fields changed
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "shadow_eval",
        -  "suggest_dataset",
        -  "extractor_dataset"
        -]New value: +[
        +  "shadow_eval",
        +  "suggest_dataset",
        +  "extractor_dataset",
        +  "activity"
        +]
      • addedInput schema / properties / month
        Added value: +{
        +  "description": "activity: the month, yyyy-mm (UTC). Defaults to the current month.",
        +  "pattern": "^\\d{4}-(0[1-9]|1[0-2])$",
        +  "type": "string"
        +}
    • Changedlbb_query11 fields changed
      • addedInput schema / properties / anchor
        Added 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"
        +}
      • addedInput schema / properties / context
        Added value: +{
        +  "description": "question: notes for the model, at most 8,000 characters: what the data means, units, names to prefer.",
        +  "type": "string"
        +}
      • addedInput schema / properties / limit
        Added 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"
        +}
      • changedInput schema / properties / mode / description
        Previous value: -"Selects the variant (one of: structured, sparql, search, analyze)."New value: +"Selects the variant (one of: structured, sparql, question, search, analyze)."
      • changedInput schema / properties / mode / enum
        Previous value: -[
        -  "structured",
        -  "sparql",
        -  "search",
        -  "analyze"
        -]New value: +[
        +  "structured",
        +  "sparql",
        +  "question",
        +  "search",
        +  "analyze"
        +]
      • changedInput schema / properties / query / description
        Previous 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."
      • addedInput schema / properties / question
        Added 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"
        +}
      • addedInput schema / properties / rerank
        Added 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"
        +}
      • addedInput schema / properties / route
        Added 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"
        +}
      • addedInput schema / properties / run
        Added value: +{
        +  "description": "question: run the query and return its rows. Defaults to true; false returns the query only.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / timeline
        Added 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. 2 tool updatesv0.8.1
    • Changedlbb_configure11 fields changed
      • changedInput schema / properties / action / description
        Previous 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)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "define_ontology",
        -  "publish_schema",
        -  "evolve_ontology"
        -]New value: +[
        +  "define_ontology",
        +  "publish_schema",
        +  "evolve_ontology",
        +  "list_starters",
        +  "apply_starter",
        +  "suggest_ontology_change"
        +]
      • addedInput schema / properties / agent
        Added value: +{
        +  "description": "Your name as the producer, shown to reviewers",
        +  "maxLength": 200,
        +  "type": "string"
        +}
      • addedInput schema / properties / anchor
        Added 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"
        +}
      • addedInput schema / properties / change
        Added 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"
        +}
      • addedInput schema / properties / evidence
        Added 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"
        +}
      • addedInput schema / properties / expected_ontology_version
        Added value: +{
        +  "description": "Refuse when the graph's ontology version differs",
        +  "minimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / key
        Added value: +{
        +  "description": "Idempotency key ([A-Za-z0-9-_.:/]); filing again with the same key revises the suggestion",
        +  "maxLength": 255,
        +  "type": "string"
        +}
      • addedInput schema / properties / rationale
        Added value: +{
        +  "description": "Why the ontology needs the change; cite what you saw",
        +  "maxLength": 4000,
        +  "type": "string"
        +}
      • addedInput schema / properties / starter
        Added value: +{
        +  "description": "Starter id: crm, documents or work (list_starters names them)",
        +  "minLength": 1,
        +  "type": "string"
        +}
      • addedInput schema / properties / title
        Added value: +{
        +  "description": "Short imperative text, e.g. 'Add class Contractor'",
        +  "maxLength": 200,
        +  "minLength": 1,
        +  "type": "string"
        +}
    • Changedlbb_inspect4 fields changed
      • changedInput schema / properties / action / description
        Previous 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)."
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • addedInput schema / properties / limit
        Added value: +{
        +  "maximum": 500,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • addedInput schema / properties / status
        Added value: +{
        +  "description": "Only suggestions in this state; default all",
        +  "enum": [
        +    "open",
        +    "accepted",
        +    "dismissed",
        +    "superseded"
        +  ],
        +  "type": "string"
        +}
  3. 2 tool updatesv0.6.0
    • Changedlbb_inspect8 fields changed
      • changedInput schema / properties / action / description
        Previous 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)."
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • changedInput schema / properties / as_of_commit_seq / description
        Previous 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."
      • removedInput schema / properties / relation
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / source_name
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / source_type
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / target_name
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / target_type
        Removed value: -{
        -  "type": "string"
        -}
    • Changedlbb_models1 field changed
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "shadow_eval",
        -  "planner_dataset",
        -  "planner_preference_dataset",
        -  "suggest_dataset",
        -  "extractor_dataset"
        -]New value: +[
        +  "shadow_eval",
        +  "suggest_dataset",
        +  "extractor_dataset"
        +]
  4. 12 tool updatesv0.5.2
    • Removedlbb_branch
    • Changedlbb_commit1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
    • Changedlbb_configure1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
    • Addedlbb_embeddings
    • Addedlbb_embeddings_delete
    • Addedlbb_embeddings_manage
    • Addedlbb_evals
    • Changedlbb_inspect1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
    • Changedlbb_models1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
    • Removedlbb_observe
    • Changedlbb_query11 fields changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
      • addedInput schema / properties / embedding
        Added 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"
        +}
      • addedInput schema / properties / explain
        Added value: +{
        +  "description": "Plan without running: the scope, the resolved filter, and the allowed count. No model call.",
        +  "type": "boolean"
        +}
      • addedInput schema / properties / filter
        Added 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"
        +}
      • addedInput schema / properties / include
        Added value: +{
        +  "description": "text: return the embedded text of each hit.",
        +  "items": {
        +    "enum": [
        +      "text"
        +    ],
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedInput schema / properties / mode / description
        Previous value: -"Selects the variant (one of: structured, sparql, analyze)."New value: +"Selects the variant (one of: structured, sparql, search, analyze)."
      • changedInput schema / properties / mode / enum
        Previous value: -[
        -  "structured",
        -  "sparql",
        -  "analyze"
        -]New value: +[
        +  "structured",
        +  "sparql",
        +  "search",
        +  "analyze"
        +]
      • addedInput schema / properties / probe
        Added value: +{
        +  "description": "Clusters to read (default 4·√clusters, at least 8). More reads cost latency and find more.",
        +  "exclusiveMinimum": 0,
        +  "type": "integer"
        +}
      • addedInput schema / properties / request
        Added 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"
        +}
      • addedInput schema / properties / text
        Added value: +{
        +  "description": "The query text (required); embedded with the graph's model.",
        +  "type": "string"
        +}
      • addedInput schema / properties / top_k / maximum
        Added value: +200
    • Changedlbb_rdf1 field changed
      • removedInput schema / properties / branch
        Removed value: -{
        -  "description": "Branch to target; defaults to the connection's branch",
        -  "type": "string"
        -}
  5. 5 tool updatesv0.5.1
    • Changedlbb_commit1 field changed
      • addedInput schema / properties / dry_run
        Added value: +{
        +  "description": "Validate a facts commit and return its structured SHACL report without writing. Only supported for mode=facts.",
        +  "type": "boolean"
        +}
    • Changedlbb_configure9 fields changed
      • changedInput schema / properties / allow_data_conflicts / description
        Previous 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."
      • addedInput schema / properties / dry_run
        Added value: +{
        +  "description": "Preview the exact definition without creating a graph or writing metadata.",
        +  "type": "boolean"
        +}
      • removedInput schema / properties / entity_types / items / additionalProperties
        Removed value: -{}
      • addedInput schema / properties / entity_types / items / anyOf
        Added value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "additionalProperties": {},
        +    "type": "object"
        +  }
        +]
      • removedInput schema / properties / entity_types / items / type
        Removed value: -"object"
      • changedInput schema / properties / ops / items / anyOf
        Previous 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"
        +  }
        +]
      • removedInput schema / properties / relations / $ref
        Removed value: -"#/properties/entity_types"
      • addedInput schema / properties / relations / items
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "string"
        +    },
        +    {
        +      "$ref": "#/properties/entity_types/items/anyOf/1"
        +    }
        +  ]
        +}
      • addedInput schema / properties / relations / type
        Added value: +"array"
    • Changedlbb_inspect5 fields changed
      • changedInput schema / properties / action / description
        Previous 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)."
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • addedInput schema / properties / cursor
        Added value: +{
        +  "description": "Opaque lbb_inspect continuation. Repeat action and pass the returned next arguments; rejects changed metadata.",
        +  "type": "string"
        +}
      • addedInput schema / properties / page_size
        Added 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"
        +}
      • addedInput schema / properties / section
        Added 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"
        +}
    • Changedlbb_query6 fields changed
      • changedInput schema / properties / as_of / description
        Previous 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."
      • changedInput schema / properties / body / description
        Previous 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."
      • addedInput schema / properties / consistency
        Added value: +{
        +  "description": "Read consistency. strong requires publication through head; a pending response is retryable.",
        +  "enum": [
        +    "eventual",
        +    "strong"
        +  ],
        +  "type": "string"
        +}
      • addedInput schema / properties / entailment
        Added 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"
        +}
      • addedInput schema / properties / min_indexed_seq
        Added value: +{
        +  "description": "Read-after-write publication floor. Preserved across cursor pages.",
        +  "maximum": 9007199254740991,
        +  "minimum": -9007199254740991,
        +  "type": "integer"
        +}
      • changedInput schema / properties / query / description
        Previous 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"
    • Addedlbb_rdf
  6. 5 tool updatesv0.4.2
    • Removedlbb_decode
    • Removedlbb_ground
    • Changedlbb_inspect5 fields changed
      • changedInput schema / properties / action / description
        Previous 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)."
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • removedInput schema / properties / direction
        Removed value: -{
        -  "enum": [
        -    "out",
        -    "in",
        -    "both"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / max_hops
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "maximum": 6,
        -  "type": "integer"
        -}
      • removedInput schema / properties / relations
        Removed value: -{
        -  "items": {
        -    "type": "string"
        -  },
        -  "type": "array"
        -}
    • Changedlbb_query2 fields changed
      • changedInput schema / properties / body / description
        Previous 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`)."
      • changedInput schema / properties / metric / enum
        Previous value: -[
        -  "entity_types",
        -  "relations",
        -  "overview",
        -  "facets",
        -  "sparql"
        -]New value: +[
        +  "entity_types",
        +  "relations",
        +  "overview",
        +  "sparql"
        +]
    • Removedlbb_search
  7. 8 tool updatesv0.2.7
    • Removedlbb_ask
    • Changedlbb_configure6 fields changed
      • changedInput schema / properties / action / description
        Previous 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)."
      • changedInput schema / properties / action / enum
        Previous value: -[
        -  "define_ontology",
        -  "define_rules",
        -  "publish_schema",
        -  "evolve_ontology"
        -]New value: +[
        +  "define_ontology",
        +  "publish_schema",
        +  "evolve_ontology"
        +]
      • removedInput schema / properties / confirm_empty
        Removed value: -{
        -  "type": "boolean"
        -}
      • changedInput schema / properties / desired_mode / enum
        Previous value: -[
        -  "warn",
        -  "reject"
        -]New value: +[
        +  "off",
        +  "warn",
        +  "reject"
        +]
      • removedInput schema / properties / preview_digest
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / rules
        Removed 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"
        -}
    • Changedlbb_decode5 fields changed
      • removedInput schema / properties / source_name / description
        Removed value: -"Source entity display name"
      • removedInput schema / properties / source_type / description
        Removed value: -"Source entity type; omit to have the DB recover it from the name"
      • removedInput schema / properties / target_name / description
        Removed value: -"Target entity display name"
      • removedInput schema / properties / target_type / description
        Removed value: -"Target entity type; omit to have the DB recover it from the name"
      • removedInput schema / properties / use_model_when_forced / description
        Removed value: -"Call the model even when the type pair forces one relation (default false — a forced pair is answered by the DB alone)"
    • Changedlbb_ground5 fields changed
      • removedInput schema / properties / action / description
        Removed value: -"complete = narrowed vocabulary autocomplete; resolve = snap free text to the nearest real vocabulary; audit = groundability report"
      • changedInput schema / properties / kinds / description
        Previous value: -"[complete/resolve] Restrict to these vocabulary kinds (default: all)"New value: +"Restrict to these vocabulary kinds (default: all)"
      • changedInput schema / properties / sample / description
        Previous value: -"[audit] Entities to sample for narrowing-recall"New value: +"[audit] Entities sampled for narrowing recall"
      • changedInput schema / properties / text / description
        Previous value: -"[resolve] Free text to snap to the nearest real vocabulary item"New value: +"[resolve] Free text to resolve"
      • changedInput schema / properties / top_k / description
        Previous value: -"[complete/resolve] Max results (default 8)"New value: +"Max results (default 8)"
    • Removedlbb_index
    • Changedlbb_inspect12 fields changed
      • changedInput schema / properties / action / description
        Previous 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)."
      • changedInput schema / properties / action / enum
        Previous 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"
        +]
      • removedInput schema / properties / base_ontology_version
        Removed value: -{
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / base_shapes_version
        Removed value: -{
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / cursor
        Removed 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"
        -}
      • removedInput schema / properties / desired_mode
        Removed value: -{
        -  "enum": [
        -    "warn",
        -    "reject"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / direction / description
        Removed value: -"Edges out of / into / touching the entity (default both)."
      • removedInput schema / properties / offset
        Removed value: -{
        -  "description": "Legacy alias for `cursor` (still accepted); prefer paging with `cursor`.",
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / ontology
        Removed 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"
        -}
      • removedInput schema / properties / relation / description
        Removed value: -"Filter to a single relation name."
      • removedInput schema / properties / row_limit
        Removed value: -{
        -  "description": "Max edges returned this page (server caps at 1000; default 150).",
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / shapes
        Removed 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"
        -}
    • Addedlbb_models
    • Changedlbb_query16 fields changed
      • removedInput schema / properties / anchor_name
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / anchor_type
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / explain
        Removed value: -{
        -  "type": "boolean"
        -}
      • removedInput schema / properties / include_derived
        Removed value: -{
        -  "type": "boolean"
        -}
      • removedInput schema / properties / max_derived
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / max_premises
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / max_rounds
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / max_solutions
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • changedInput schema / properties / mode / description
        Previous value: -"Selects the variant (one of: structured, sparql, shacl, infer, retrieval_premises, analyze)."New value: +"Selects the variant (one of: structured, sparql, analyze)."
      • changedInput schema / properties / mode / enum
        Previous value: -[
        -  "structured",
        -  "sparql",
        -  "shacl",
        -  "infer",
        -  "retrieval_premises",
        -  "analyze"
        -]New value: +[
        +  "structured",
        +  "sparql",
        +  "analyze"
        +]
      • removedInput schema / properties / query_top_k
        Removed value: -{
        -  "exclusiveMinimum": 0,
        -  "type": "integer"
        -}
      • removedInput schema / properties / relation
        Removed value: -{
        -  "type": "string"
        -}
      • removedInput schema / properties / rules
        Removed 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"
        -}
      • removedInput schema / properties / shacl_mode
        Removed value: -{
        -  "description": "select returns focus nodes; validate returns a report",
        -  "enum": [
        -    "select",
        -    "validate"
        -  ],
        -  "type": "string"
        -}
      • removedInput schema / properties / shapes
        Removed value: -{
        -  "items": {
        -    "$ref": "#/properties/body"
        -  },
        -  "type": "array"
        -}
      • removedInput schema / properties / threshold
        Removed value: -{
        -  "maximum": 1,
        -  "minimum": 0,
        -  "type": "number"
        -}
  8. 11 tool updatesv0.2.1
    • First observedlbb_ask
    • First observedlbb_branch
    • First observedlbb_commit
    • First observedlbb_configure
    • First observedlbb_decode
    • First observedlbb_ground
    • First observedlbb_index
    • First observedlbb_inspect
    • First observedlbb_observe
    • First observedlbb_query
    • First observedlbb_search

TDQS

A4/5.0

Scored across 10 tools

Disambiguation4/5

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.

Naming Consistency4/5

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.

Tool Count4/5

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.

Completeness4/5

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

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    An 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.
    13
    1
    MIT