Skip to main content
Glama
littlebigbrains

@littlebigbrain/mcp

lbb_query

Read-only

Query Little Big Brain knowledge graphs using structured SPARQL-subset JSON, SPARQL text, SHACL validation, inference rules, or analytics. Supports pagination, grouping, aggregations, and snapshot pinning.

Instructions

Analytical and expert reads. Modes: structured (SPARQL-subset JSON body), sparql (SPARQL text), shacl, infer, retrieval_premises, analyze. 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 (see the sparql/structured field hints, and lbb_inspect action=ontology for exact names). For structured/sparql row paging, MCP owns limit/offset via row_limit/cursor; a cursor reuses the original query/body and pins continuation pages to the original head commit. When a single page's rows are complete server-side (row_page.has_more false) but too large for one MCP result, the envelope reports rows_shown (fewer than row_page.returned), keeps truncated: true, and hands back a next cursor that pages the same result set at a smaller row_limit — so a large fully-returned result is never silently cut without a way to read the rest.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
bodyNoStructured 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`).
modeYesSelects the variant (one of: structured, sparql, shacl, infer, retrieval_premises, analyze).
as_ofNoSnapshot 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.
chartNo
fieldNo
graphNoGraph to target; defaults to the connection's graph
queryNoSPARQL 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
rulesNo
top_kNo
branchNoBranch to target; defaults to the connection's branch
cursorNoOpaque cursor from a previous lbb_query row page; reruns the original query at the next offset.
detailNoResponse detail level. Defaults to compact.
metricNo
shapesNo
sparqlNo
explainNo
relationNo
row_limitNoMaximum query rows to return in this page. Defaults by detail: compact=20, standard=100, full=1000.
thresholdNo
max_roundsNo
shacl_modeNoselect returns focus nodes; validate returns a report
anchor_nameNo
anchor_typeNo
max_derivedNo
query_top_kNo
max_premisesNo
max_solutionsNo
include_derivedNo
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).
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint annotation, the description extensively discloses behaviors: pagination with cursor, truncation handling, auto-lowercasing of IRIs with notes, snapshot pinning via as_of/as_of_commit_seq, and response envelope structure. It also explains that the tool is read-only and that it will never silently cut large results. 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.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very long and densely packed with details. While necessary for a complex tool with 29 parameters and deep nesting, it could be better structured with sections or bullet points to improve readability. The front-loading of the main purpose and modes is good, but the extensive parameter documentation is not scannable.

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?

Despite lacking an output schema, the description covers all important aspects: all six modes, parameter shapes and defaults, pagination mechanism, snapshot semantics, rule engine behavior, and error handling (e.g., single-page truncation). It gives complete examples for structured and grouped queries. The only minor gap is absence of output schema, but the envelope explanation suffices.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With only 38% schema description coverage, the description compensates with rich parameter details: the complex body schema (patterns, filters, group_by with examples), mode enum semantics, cursor and row_limit interaction, and rule syntax with combinators. It provides runnable examples and clarifies constraints (e.g., bare as_of inside body rejected). This far exceeds what the schema alone conveys.

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 clearly states the tool's purpose as 'Analytical and expert reads' with multiple modes (structured, sparql, shacl, infer, retrieval_premises, analyze). It provides a specific verb+resource scope. However, it does not explicitly differentiate from sibling tools like lbb_inspect or lbb_observe, leaving the agent to infer when to use this over alternatives.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description lacks explicit guidance on when to use lbb_query versus sibling tools (lbb_inspect, lbb_ask, etc.). While it details how each mode works, it does not state prerequisites, exclusions, or contextual triggers for switching between tools. The agent must infer usage from the general read-only nature.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/littlebigbrains/lbb-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server