lindas-mcp
This server wraps the LINDAS Swiss linked-data SPARQL knowledge graph in guarded MCP tools for discovering and reading statistical data cubes.
search_cubes — find statistical data cubes by topic, language, publisher, and version filtering.
get_cube_structure — inspect a cube's dimensions, measures, code lists, and licence before querying data.
query_cube_observations — retrieve actual data points, automatically resolving coded values into human-readable labels.
list_publishers — list federal bodies publishing cubes, with cube counts, to narrow searches.
resolve_municipality — map Swiss municipality names to LINDAS URIs and BFS numbers, the portfolio join key.
run_sparql — advanced escape hatch for raw SPARQL SELECT queries, capped and guarded against timeouts.
api_status — check endpoint reachability and cube count, distinguishing outages from empty results.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@lindas-mcpSearch for cubes about forest fire danger in Switzerland"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Part of the Swiss Public Data MCP Portfolio — a collection of open-source MCP servers connecting AI agents to Swiss public and open data. This is a private project. It is not affiliated with, endorsed by, or operated on behalf of any employer or public authority.
lindas-mcp
MCP server for LINDAS — the linked-data knowledge graph of the Swiss administration.
What LINDAS is
LINDAS (Linked Data Service) is the Swiss Confederation's SPARQL knowledge graph, run by the Federal Archives. Instead of tables, it publishes data as RDF triples: around 2000 statistical data cubes (cube.link) from federal offices, plus the geo-linked data that powers visualize.admin.ch.
Mnemonic: «I14Y is the library catalogue, LINDAS is the library itself.» i14y-mcp tells you a dataset exists. LINDAS holds the data and lets you query across all of it at once.
This server wraps LINDAS in guarded tools rather than exposing raw SPARQL, because the store rewards precise queries and times out on broad ones.
Related MCP server: Zurich Open Data MCP Server
🎯 Anchor Demo Query
«Which forest-fire danger level currently applies, who publishes it, and under which licence?»
search_cubes(query="waldbrand")
→ «Waldbrandgefahr» — BAFU, published
get_cube_structure(cube_uri=...)
→ dimensions: Warnregion (key), Gefahrenstufe (measure)
→ licence: fedlex.data.admin.ch/eli/cc/1984/... (a Fedlex URI!)
query_cube_observations(cube_uri=...)
→ Warnregion: "Dorneck / Thierstein (SO)", Gefahrenstufe: "grosse Gefahr"The codes come back as labels — «grosse Gefahr», not 4. And the licence is a
Fedlex URI you can resolve with fedlex-mcp.
Demo
The two-phase access pattern
LINDAS cubes are self-describing but coded. Reading them well means two steps, which this server enforces:
Structure first —
get_cube_structurereads the cube's SHACL shape: its dimensions (filterable axes), its measures (the numbers), and which dimensions carry code lists.Data second —
query_cube_observationsreads the observations and resolves coded values to human labels using the structure from step 1.
Mnemonic: «LINDAS speaks in postcodes, not place names.» An observation says region
1805; the server turns that into «Alpennordhang» for you.
Architecture
┌──────────────────────────────┐
│ MCP Host (Claude) │
└───────────────┬──────────────┘
│ stdio | streamable-http
┌───────────────▼──────────────┐
│ lindas-mcp │
│ ┌────────────────────────┐ │
│ │ server.py (7 tools) │ │ talks only to cube.py
│ ├────────────────────────┤ │
│ │ lindas/cube.py │ │ ← vocabulary guardrail,
│ │ │ │ two-phase access,
│ │ │ │ code→label resolution
│ ├────────────────────────┤ │
│ │ lindas/queries.py │ │ SPARQL templates,
│ │ │ │ all anchored on a class
│ ├────────────────────────┤ │
│ │ lindas/client.py │ │ raw SPARQL over HTTP,
│ │ │ │ knows nothing of cubes
│ └────────────────────────┘ │
└───────────────┬──────────────┘
│ HTTPS, no auth
┌───────────────▼──────────────┐
│ lindas.admin.ch/query │
│ SPARQL 1.1 · ~2000 cubes │
└──────────────────────────────┘The lindas/ package is deliberately layered so it can be lifted into other
LINDAS-backed servers unchanged. client.py knows only HTTP and SPARQL;
cube.py knows the cube.link vocabulary; the tools know only cube.py. Raw
SPARQL never reaches the agent except through the guarded run_sparql escape
hatch.
Architecture decision
Architecture A (live SPARQL only), with a strict vocabulary guardrail.
Verified live on 2026-07-21:
The endpoint is stable, needs no authentication, and returns a clean HTTP 400 with a diagnostic on malformed queries.
Blind scans (
SELECT *,COUNT(*)over the whole store) time out at 60–90 s; the same question anchored on?x a cube:Cubeanswers in ~2 s.
Consequences, baked into the tools:
Every query template is anchored on a known class. No unbounded scans.
Two-phase access is enforced; the agent never sees raw codes.
run_sparqlis capped at 500 rows and 30 s and marked as advanced.The client timeout sits at 45 s, in front of the store's own 60–90 s abort.
Full probe report: docs/probe-lindas.md.
Tools
Tool | Purpose |
| Find cubes by topic. Entry point. Deduplicates versions. |
| Phase 1: dimensions, measures, licence. |
| Phase 2: data points with codes resolved to labels. |
| Federal bodies publishing cubes, with counts. |
| Name ↔ URI ↔ BFS number — the portfolio join key. |
| Advanced escape hatch. Capped, guarded. |
| Reachability check with cube count. |
All tools are annotated readOnlyHint: true.
Installation
uvx lindas-mcpClaude Desktop
{
"mcpServers": {
"lindas": {
"command": "uvx",
"args": ["lindas-mcp"]
}
}
}Remote deployment
LINDAS_MCP_TRANSPORT=sse PORT=8000 lindas-mcpLINDAS_MCP_TRANSPORT accepts stdio (default), sse or streamable-http.
The SSE / streamable-http transport binds to HOST, default 127.0.0.1;
set HOST=0.0.0.0 explicitly to expose it (only behind a reverse proxy). For a
hosted HTTP deployment, set ALLOWED_ORIGINS to a comma-separated list of
browser origins — unset means no browser client is permitted at all, which
is the default. * is still accepted and logs a warning. LOG_LEVEL tunes the
JSON stderr logs.
Docker
docker compose up --build # binds 0.0.0.0 inside the container, publishes :8000The image runs as a non-root user, read-only, with resource limits and a
TCP health check (see Dockerfile and compose.yaml).
Join keys
LINDAS is a connector layer, and two of its identifiers make it composable with the rest of the portfolio:
Key | Where | Joins to |
BFS commune number |
| swiss-statistics-mcp, zurich-opendata-mcp |
Fedlex URI | cube |
The Fedlex link is the quiet surprise: many cubes declare their licence as a
legal-basis URI (fedlex.data.admin.ch/eli/cc/...), so you can go from a data
point straight to the law that governs it.
Known limitations
Verified live on 2026-07-21.
Broad SPARQL times out. The store aborts unanchored scans at 60–90 s. The guarded tools avoid this;
run_sparqlwarns about it and caps runtime.Observations are coded. Dimension values are URIs, not labels. The server resolves them via each dimension's code list, but resolution costs one extra query per coded dimension. Set
resolve_labels=Falseto skip it.No server-side observation filtering by arbitrary value. LINDAS has no cheap way to filter observations by a dimension value inside a cube, so
query_cube_observationsreads the first N observations. Analytical slicing belongs inrun_sparql.Licences vary per cube and are declared as
dcterms:license, frequently a Fedlex URI rather than a plain name. Always surface thelicencefield.Version handling is heuristic.
search_cubesdeduplicates by stripping the version suffix from the cube URI and keeping the highestschema:versionamong published cubes. Unusual URI shapes may not collapse cleanly; uselatest_only=Falseto inspect every version.
MCP Protocol Version
This server speaks two protocol eras over the same endpoint. The client's first request on a connection decides which one applies; a later claim from the other era is refused.
Era | Revision | Who reaches it |
|
| What today's clients speak. The server answers with the revision asked for, or with the |
Per-request envelope |
| A request carrying the |
Both revisions are pinned in
tests/test_protocol_version.py and asserted
against the installed SDK, so a Dependabot bump of mcp cannot move either one
silently. The handshake ceiling is measured against a live initialize through
the assembled ASGI stack, not read off a constant name.
Note that the SDK's LATEST_PROTOCOL_VERSION is an alias for the modern
era, not for the handshake era — pinning against it alone would leave the era
that current clients actually negotiate free to drift.
Update policy. When the gate fails, do not edit the constant blindly: read
the spec changelog between the two revisions, verify the server still behaves,
then move the constant, this section, README.de.md and
CHANGELOG.md together.
Testing
PYTHONPATH=src pytest tests/ -m "not live" # offline, used in CI
PYTHONPATH=src pytest tests/ -m "live" # hits the real endpoint
python -m ruff check src testsThe live tests earn their place: the observationSet indirection (a cube's
observations hang off cube:observationSet, never directly off the cube) is a
structural assumption that a mock cannot validate. It is covered by a live test.
Contributing
See CONTRIBUTING.md for the ground rules (read-only, one
egress host, anchored queries) and the local dev loop. Further reading:
EXAMPLES.md for use cases by audience with the tool-selection
table, docs/roadmap.md for the project phase, and
PUBLISHING.md for the PyPI / MCP Registry release process.
Security
See SECURITY.md for the security posture and how to report a
vulnerability.
License
MIT License — see LICENSE. The LINDAS data remains subject to the licence each publisher declares on the cube.
Author
Hayal Oezkan · github.com/malkreide
Credits & related projects
Data: LINDAS Linked Data Service, Swiss Federal Archives
Vocabulary: cube.link
Visualisation frontend on the same cubes: visualize.admin.ch
Source discovery inspired by rnckp/awesome-ogd-switzerland
Portfolio: swiss-public-data-mcp
Licence: MIT. The cube data remains subject to the licence each publisher declares.
MCP Registry
Ownership marker used by the MCP Registry to link this PyPI package to the GitHub namespace:
mcp-name: io.github.malkreide/lindas-mcpMCP protocol version
The negotiated MCP protocol version is managed by the pinned mcp SDK
(mcp>=1.28.1 in pyproject.toml), which Dependabot keeps current. SDK upgrades
are therefore a reviewed change: any protocol-affecting bump is called out in
CHANGELOG.md, and the tool contract is guarded independently by
tool-definitions.lock.json (SEC-022) so a change to the tool surface fails CI
until reviewed.
Available Tools
7 toolsapi_statusARead-onlyIdempotent
Check whether the LINDAS SPARQL endpoint is reachable.
Returns an evaluable status even on failure, so an agent can tell "no data matched" apart from "the endpoint is down".
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| note | Yes | |
| source | No | |
| endpoint | Yes | |
| reachable | Yes | |
| cube_count | No | |
| provenance | No | |
| retrieved_at | Yes | |
| last_successful_call | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds crucial failure behavior: even on failure, the status is evaluable, allowing differentiation between data absence and endpoint outage. This is valuable beyond the annotations and contains no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loaded with the core purpose and followed by a concise behavioral note. Every sentence adds value; no fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (no parameters), the presence of an output schema, and rich annotations, the description fully covers purpose, failure behavior, and the diagnostic use case. No missing critical information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With zero parameters, the schema is trivially covered. The baseline for no parameters is 4, and the description need not elaborate on parameter meanings. Nothing additional is required.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb+resource: 'Check whether the LINDAS SPARQL endpoint is reachable.' This unambiguously identifies the tool's purpose and differentiates it from siblings that query data or manage cubes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when the tool is valuable: 'Returns an evaluable status even on failure, so an agent can tell "no data matched" apart from "the endpoint is down".' This provides clear context for use, though it does not explicitly name alternative tools or exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_cube_structureARead-onlyIdempotent
Read a cube's dimensions and measures — always call this before data.
This is phase 1 of the two-phase access pattern. It tells you which
dimensions you can filter on (KeyDimension), which values are measured
(MeasureDimension), and which dimensions carry code lists. It also
returns the licence, which is frequently a Fedlex URI you can resolve with
fedlex-mcp.
Args:
cube_uri: A cube URI from search_cubes.
language: Language for dimension names and description.
| Name | Required | Description | Default |
|---|---|---|---|
| cube_uri | Yes | ||
| language | No | de |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | No | |
| source | No | |
| status | No | |
| licence | No | Often a Fedlex URI — joins to fedlex-mcp. |
| version | No | |
| cube_uri | Yes | |
| dimensions | Yes | |
| provenance | No | |
| description | No | |
| creator_name | No | |
| retrieved_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as read-only, idempotent, and non-destructive. The description adds valuable behavioral context beyond those hints: it returns a licence that is often a Fedlex URI, and it discloses the semantic structure of the response (KeyDimension, MeasureDimension). There is no contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with a concise purpose statement followed by a compact explanation of what the tool tells the agent. The Args section is clearly separated and each sentence delivers useful information without filler. It is appropriately sized for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema, the description does not need to detail return structure. It covers the tool's role in the workflow, parameter semantics, the licensing edge case, and its relationship to sibling tools, making it complete for a read-only structure-resolution tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has no descriptions for cube_uri or language (0% schema description coverage), so the description carries the full burden. The Args section explains that cube_uri comes from search_cubes and that language controls dimension names and descriptions, fully compensating for the schema's lack of semantic detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Read a cube's dimensions and measures') and immediately differentiates from siblings by labeling it 'phase 1' of the two-phase access pattern. It also clarifies what kind of data is returned (dimensions, measures, code lists), distinguishing it from query_cube_observations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states 'always call this before data' and frames the tool as 'phase 1', telling the agent exactly when to invoke it. It also describes what information the tool reveals (filterable dimensions, measured values, code lists) and how to handle the licence (Fedlex URI resolution), providing clear decision guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_publishersARead-onlyIdempotent
List the federal bodies that publish cubes, with cube counts.
Returns creator URIs you can pass to search_cubes to restrict a search
to one authority.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| source | No | |
| returned | Yes | |
| provenance | No | |
| publishers | Yes | |
| retrieved_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate read-only and non-destructive behavior, and the description adds valuable context about the return value (creator URIs and cube counts) without contradicting the annotations. It could mention more about open-world semantics, but that is already hinted by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is only two sentences, front-loaded with the core purpose, followed by a practical usage note. Every sentence earns its place with no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with a rich output schema and annotations, the description fully covers the purpose, what is returned, and how the output integrates with a sibling tool. It is complete for an agent to select and invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there is nothing to document. The baseline score of 4 applies, and the description correctly focuses on the output and usage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('List') and resource ('federal bodies that publish cubes') and adds that it includes cube counts. It distinguishes itself from siblings by explaining the output can be used with search_cubes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on how to use the returned creator URIs with search_cubes, implying a clear use case. It does not explicitly state when not to use it or alternatives, but the context is sufficient.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
query_cube_observationsARead-onlyIdempotent
Read the actual data points of a cube, with codes resolved to labels.
This is phase 2. Values are returned keyed by human-readable dimension names, and coded dimension values (e.g. region "1805") are replaced by their labels (e.g. "Alpennordhang") unless you turn that off.
For large cubes this reads only the first limit observations. LINDAS has
no cheap way to filter observations server-side by arbitrary dimension
value, so heavy analytical slicing belongs in run_sparql.
Args:
cube_uri: A cube URI from search_cubes.
language: Language for labels.
limit: Maximum observations to return (1-500).
resolve_labels: Replace coded values with human labels.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| cube_uri | Yes | ||
| language | No | de | |
| resolve_labels | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| source | No | |
| licence | No | |
| cube_uri | Yes | |
| returned | Yes | |
| cube_name | No | |
| provenance | No | |
| observations | Yes | |
| retrieved_at | Yes | |
| labels_resolved | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate read-only, idempotent, and non-destructive behavior. The description adds valuable context about the limit on observations, label resolution toggle, and the inability to filter server-side, going beyond annotation basics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a brief overview, a contextual note about limitations, and an Args list. Every sentence provides essential information without redundancy, making it appropriately concise yet informative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema and strong annotations, the description fully covers the tool's purpose, limitations, and usage context. It mentions the 'phase 2' pipeline position and provides the needed alternative for heavy queries, making it complete for invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although the schema lists parameters, the description gives each parameter semantic meaning: cube_uri from search_cubes, language for labels, limit as observation cap, and resolve_labels toggling label replacement. This clarifies how each parameter affects behavior.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool 'Read the actual data points of a cube' with a specific resource and action. It adds details about label resolution and keying by dimension names, distinguishing it from sibling tools like run_sparql.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to use this for reading observations and to use run_sparql for heavy analytical slicing, noting the lack of cheap server-side filtering. This provides clear when-to-use and when-not-to-use guidance with a named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolve_municipalityARead-onlyIdempotent
Resolve a Swiss municipality to its LINDAS URI and BFS number.
The BFS commune number is the join key across the whole portfolio: the same number identifies the municipality in swiss-statistics-mcp, zurich-opendata-mcp and any cube that references a place. In LINDAS the URI is literally ld.admin.ch/municipality/.
Args: name_or_bfs: A municipality name ("Zürich") or a BFS number ("261"). language: Language for the name.
| Name | Required | Description | Default |
|---|---|---|---|
| language | No | de | |
| name_or_bfs | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| query | Yes | |
| source | No | |
| returned | Yes | |
| match_type | No | 'none' when the name/BFS number resolved to nothing. |
| provenance | No | |
| suggestion | No | Actionable next step when match_type is 'none'. |
| retrieved_at | Yes | |
| municipalities | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish the operation as read-only and idempotent. The description adds valuable behavioral context beyond annotations, including the exact URI format ('ld.admin.ch/municipality/<BFS>') and the BFS number's role as a universal identifier. No contradiction exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: a clear first sentence states the purpose, a short paragraph provides contextual significance, and an Args list documents parameters. Every sentence earns its place with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple resolution tool with read-only annotations and an output schema, the description covers the essential purpose, parameter semantics, and contextual significance. The presence of an output schema means return values need not be detailed in the description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has no parameter descriptions (0% coverage), so the description's Args section is essential. It fully explains name_or_bfs with examples ("Zürich" or "261") and clarifies that language specifies the language for the name, compensating completely for the schema's lack of detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Resolve a Swiss municipality to its LINDAS URI and BFS number.' This provides a specific verb and outcome, and it is distinct from sibling tools like search_cubes or query_cube_observations, which focus on data cubes rather than municipality resolution.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the BFS number as the join key across the portfolio, strongly implying when to use this tool for cross-tool consistency. It does not explicitly name alternatives or exclusion scenarios, but the context is clear enough to guide an agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_sparqlARead-onlyIdempotent
Run a raw SPARQL SELECT query. Advanced escape hatch — use sparingly.
Prefer the structured tools. This exists for analytical queries the guarded tools cannot express (cross-cube joins, aggregations, custom filters).
Guardrails, learned from probing: LINDAS times out on unanchored scans, so
always anchor on a known class such as ?x a <https://cube.link/Cube>.
A bare SELECT * WHERE { ?s ?p ?o } will time out. This tool caps the
result at 500 rows and the runtime at 30 seconds.
Args: query: A complete SPARQL SELECT query, including its own PREFIX lines.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | Yes | |
| rows | Yes | |
| source | No | |
| row_count | Yes | |
| provenance | No | |
| retrieved_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint, idempotentHint), the description discloses result caps (500 rows), runtime limit (30 seconds), and timeout behavior on unanchored scans. This is valuable behavioral context that annotations do not provide, and it does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is somewhat lengthy but well-structured: it starts with purpose, then usage guidance, guardrails, and parameter details. Each sentence adds value, though the guardrails paragraph could be slightly more compact without losing important information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the existence of an output schema, the description fully addresses purpose, usage rules, parameter requirements, and operational pitfalls (timeouts, caps). No significant gaps remain for a raw query tool of this complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only defines 'query' as a string, but the description adds critical requirements: 'a complete SPARQL SELECT query, including its own PREFIX lines.' This clarifies what the parameter must contain, though it stops short of providing a full example or specifying SPARQL dialect details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Run a raw SPARQL SELECT query' and distinguishes this from sibling structured tools by positioning it as an 'advanced escape hatch' for analytical queries they cannot express, such as cross-cube joins and aggregations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs to 'Prefer the structured tools' and specifies when this tool is appropriate: analytical queries the guarded tools cannot express (cross-cube joins, aggregations, custom filters). It also provides concrete implementation guidance, such as always anchoring on a known class to avoid timeouts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_cubesARead-onlyIdempotent
Find statistical data cubes in LINDAS by topic.
The entry point. Returns cube URIs you then pass to get_cube_structure.
By default only the newest published version of each cube is returned;
set latest_only=False to see every version.
Args:
query: Topic term, e.g. "Wald", "Abfluss", "Energie". Matched against
cube names and descriptions in the chosen language.
language: Language for names and descriptions.
creator_uri: Restrict to one publishing body (from list_publishers).
limit: Maximum cubes to return (1-100).
latest_only: Collapse versions to the newest per cube.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| language | No | de | |
| creator_uri | No | ||
| latest_only | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| cubes | Yes | |
| query | Yes | |
| source | No | |
| language | Yes | |
| returned | Yes | |
| match_type | No | 'none' when nothing matched — distinguishes a real miss from an error. |
| provenance | No | |
| suggestion | No | Actionable next step when match_type is 'none' (e.g. which tool to try). |
| latest_only | Yes | |
| retrieved_at | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
While annotations already indicate read-only, open-world, and idempotent behavior, the description adds non-obvious context: 'By default only the newest published version of each cube is returned; set latest_only=False to see every version.' It also clarifies query matching semantics against names and descriptions in the chosen language, going well beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured: a one-sentence purpose, a workflow note, a behavioral default, then a terse Args list. Every sentence contributes value, with no redundancy or fluff, making it easy for an agent to scan and retain.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 5 parameters and an output schema, the description covers the tool's role, integration with siblings, all parameter semantics, and key version-collapse behavior. The output schema handles return values, so no further explanation is needed. The description is fully adequate for correct selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden. It does so with a dedicated Args block explaining every parameter, providing example values for query, the source for creator_uri, a range for limit, and the meaning of latest_only. This adds substantial meaning beyond the bare schema titles.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Find statistical data cubes in LINDAS by topic,' clearly stating the verb, resource, and scope. It further distinguishes itself from sibling tools by noting that it returns cube URIs to be passed to get_cube_structure, establishing a specific role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly labels the tool 'The entry point' and instructs that returned URIs should be passed to get_cube_structure, creating a clear workflow. It also mentions that creator_uri comes from list_publishers, tying the tool to its siblings and giving practical when-to-use guidance.
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. Dates show when Glama detected each change.
7 tool updates
v0.2.0- First observed
api_status - First observed
get_cube_structure - First observed
list_publishers - First observed
query_cube_observations - First observed
resolve_municipality - First observed
run_sparql - First observed
search_cubes
TDQS
Every tool has a clearly distinct role: searching cubes, inspecting structure, fetching observations, listing publishers, resolving municipalities, running raw SPARQL, and checking status. There is no overlap or ambiguity in their purposes.
Most tools follow a consistent verb_noun pattern (search_cubes, get_cube_structure, query_cube_observations, list_publishers, resolve_municipality, run_sparql). The slight deviation is 'api_status', which reads as a noun phrase rather than an imperative verb, but it is still recognizable and not jarring.
Seven tools is well within the ideal range for a focused data-access server. Each tool addresses a necessary step in the workflow without redundancy or bloat.
The tool surface covers the full data access cycle: discover (search_cubes, list_publishers), understand (get_cube_structure), retrieve (query_cube_observations), and handle edge cases (run_sparql, resolve_municipality, api_status). There are no obvious dead ends or missing operations for the stated domain.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
DBpedia MCP — SPARQL + Lookup over Wikipedia-derived structured data
opendata.swiss MCP — Switzerland's federal open-data portal (CKAN catalogue).
Keyless open data for 84 German cities: 12 lean read-only MCP tools covering 67 data types.
MCP gateway federating 22 biomedical MCP servers behind one endpoint: gnomAD, ClinVar, HPO, VEP.
Related MCP Servers
- AlicenseAqualityDmaintenanceAn MCP server for discovering, downloading, querying, and analyzing datasets from Ontario's open data portals, allowing natural language questions and high-performance analytics via DuckDB.231MIT
- AlicenseBqualityAmaintenanceAn MCP server providing AI-powered access to Open Data from the City of Zurich, enabling queries to 900+ datasets, real-time environmental and mobility data, geodata, parliamentary proceedings, and more.268MIT
- AlicenseAqualityCmaintenanceMCP server exposing SPARQL query functionalities for LLMs, enabling query execution, validation, and graph exploration across SPARQL endpoints.7MIT
- FlicenseAqualityCmaintenanceEnables LLMs to query structured statistical data from the Swiss Federal Archives' Linked Data platform (LINDAS) by translating natural language questions into SPARQL queries against RDF data cubes.8-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/malkreide/lindas-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server