LINDAS MCP Server

LINDAS MCP Server

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

Category
访问服务器

README

LINDAS MCP Server

A Model Context Protocol server that enables LLMs to query structured data from LINDAS — the Swiss Federal Archives' Linked Data platform at https://ld.admin.ch.

LINDAS stores multi-dimensional statistical data as RDF cubes using the cube.link vocabulary, accessible via a SPARQL endpoint backed by Stardog. This server translates high-level tool calls into SPARQL queries and returns clean, LLM-friendly JSON.

What this enables

Ask an LLM questions about Swiss federal data and let it discover, inspect, and query datasets automatically:

  • "Show me forest fire danger warnings in the last week"
  • "Compare population across all cantons for 2023"
  • "Find datasets about unemployment"

The LLM uses the tools below to discover cubes, inspect their structure, find valid dimension values, and query observations — all without writing SPARQL.

Prerequisites

  • Node.js ≥ 20
  • npm or pnpm

Installation

npm install
npm run build

Configuration

Environment variables (all optional):

Variable Default Description
LINDAS_SPARQL_ENDPOINT https://ld.admin.ch/query SPARQL endpoint URL
LINDAS_DEFAULT_LANGUAGE de Default language for labels (de, fr, it, en)
LINDAS_TRANSPORT stdio Transport mode: stdio or http
LINDAS_PORT 3000 HTTP port (only used when transport is http)
LINDAS_HOST 0.0.0.0 HTTP bind address (only used when transport is http)

Command-line flags override environment variables:

lindas-mcp [--transport stdio|http] [--port PORT]

Usage with Claude Desktop

Add the server to your claude_desktop_config.json:

{
  "mcpServers": {
    "lindas": {
      "command": "node",
      "args": ["C:/path/to/lindas-mcp/dist/index.js"],
      "env": {
        "LINDAS_DEFAULT_LANGUAGE": "de"
      }
    }
  }
}

For development with hot reload, use tsx:

{
  "mcpServers": {
    "lindas": {
      "command": "npx",
      "args": ["tsx", "C:/path/to/lindas-mcp/src/index.ts"]
    }
  }
}

HTTP Transport (Streamable HTTP)

For use with the MCP Inspector, web-based clients, or remote access, start the server in HTTP mode:

# Using npm scripts
npm run start:http          # node dist/index.js --transport http
npm run dev:http            # tsx src/index.ts --transport http

# Or directly
node dist/index.js --transport http --port 3000

The server exposes the MCP Streamable HTTP endpoint at http://127.0.0.1:3000/mcp.

In HTTP mode, each client session gets its own MCP server instance. The server tracks sessions via the Mcp-Session-Id header.

MCP Inspector

To inspect the server interactively, open the MCP Inspector and connect to:

http://127.0.0.1:3000/mcp

Or launch the Inspector with the server:

npx @modelcontextprotocol/inspector node dist/index.js --transport stdio

opencode

For HTTP mode in opencode, configure opencode.json:

{
  "mcp": {
    "lindas": {
      "type": "remote",
      "url": "http://127.0.0.1:3000/mcp",
      "enabled": true
    }
  }
}

LibreChat / Docker

Build the Docker image and add it to your docker-compose.yml:

services:
  lindas-mcp:
    image: lindas-mcp
    container_name: lindas-mcp
    environment:
      - LINDAS_TRANSPORT=http
      - LINDAS_PORT=8000
      - LINDAS_DEFAULT_LANGUAGE=de
    restart: unless-stopped
    # ports:                    # Only needed for host access
    #   - "8000:8000"

Then in LibreChat's config:

mcpServers:
  lindas:
    type: streamable-http
    url: http://lindas-mcp:8000/mcp

Make sure both containers share the same Docker network.

Available Tools

Discovery & Search

Tool Description Key Parameters
list_cubes List available data cubes limit, offset
search_datasets Full-text search across cube titles/descriptions query, limit
get_cube_metadata Get publisher, license, status, temporal coverage, and other metadata for a cube cube_uri
get_cube_versions List all versions of a cube cube_uri
get_cube_structure Get dimensions/measures/datatypes of a cube cube_uri
get_dimension_summary Get all dimensions with value counts and available ranges — single-call overview instead of calling get_dimension_values for each dimension separately cube_uri, language

Querying

Tool Description Key Parameters
query_observations Query observations with filters, pagination, and optional label resolution cube_uri, dimensions, measures, filters, resolve_labels, limit, offset, language
count_observations Count observations (check size before query) cube_uri, filters
count_observations_by_dimension Break down observation counts by dimension values (e.g., how many per canton per year) cube_uri, dimension, filters, limit, language
get_page_info Get pagination metadata for a query — total count, hasMore, nextPageOffset cube_uri, dimensions, measures, filters, limit, offset

Geography

Tool Description Key Parameters
get_cantons List all 26 Swiss cantons with IRIs and names language
get_municipalities List Swiss municipalities with IRIs and names (optionally filtered by canton) canton_iri, language
get_districts List Swiss districts with IRIs and names (optionally filtered by canton) canton_iri, language
resolve_geography Resolve a place name to its LINDAS IRI name, language
resolve_iri Look up a LINDAS IRI to get its label and type iri, language

Resources

  • lindas:///cubes — Catalogue of available data cubes (Markdown)

Prompts

  • data_exploration — Step-by-step guide for exploring LINDAS data
  • canton_comparison — Compare a topic across cantons for a given year (args: topic, year)

Typical Workflow

The recommended workflow for an LLM using this server:

  1. search_datasets or list_cubes — Find cubes matching the user's topic
  2. get_cube_structure — Inspect the cube's dimensions and measures
  3. get_dimension_summary — Get a quick overview of all dimensions with value counts (replaces calling get_dimension_values for each dimension separately)
  4. resolve_geography — If the user mentions a place name, resolve it to an IRI
  5. resolve_iri — If query results contain opaque IRIs, look up their labels
  6. count_observations — Check how many results the query will return
  7. query_observations — Retrieve the data (use resolve_labels: true to get human-readable labels instead of IRIs)

For geographic comparisons, use get_cantons, get_municipalities, or get_districts to list geographic entities with their IRIs.

resolve_labels Feature

When query_observations is called with resolve_labels: true, IRI-valued dimensions are automatically joined to their schema:name labels. Instead of receiving:

{ "canton": { "value": "https://ld.admin.ch/canton/1", "label": "https://ld.admin.ch/canton/1" } }

You receive:

{ "canton": { "value": "https://ld.admin.ch/canton/1", "label": "Zürich" } }

This makes results immediately understandable without additional lookups.

Development

npm run dev          # Start stdio transport with tsx (hot reload)
npm run dev:http     # Start HTTP transport with tsx (hot reload)
npm run build        # Compile with tsc
npm start            # Run compiled stdio server
npm run start:http   # Run compiled HTTP server
npm test             # Run unit tests (vitest)
npm run test:watch   # Watch mode

Project Structure

src/
├── index.ts              # MCP server entry point (stdio + HTTP)
├── config.ts             # Configuration constants
├── sparql/
│   ├── client.ts         # SPARQL HTTP client + SparqlError
│   ├── queryBuilder.ts   # Pure SPARQL query builder functions
│   └── resultParser.ts   # SPARQL JSON → domain object parsers
├── tools/
│   ├── index.ts          # Tool registration + dispatch
│   └── *.ts              # Individual tool handlers
├── resources/
│   └── catalogue.ts      # lindas:///cubes resource
└── prompts/
    └── templates.ts      # Prompt templates
tests/
├── sparql.test.ts        # Query builder unit tests
└── resultParser.test.ts  # Parser unit tests

Notes

  • All logging goes to stderr (stdout is reserved for the MCP protocol in stdio mode).
  • User input interpolated into SPARQL is escaped to prevent injection.
  • Result limit is capped at 500 to protect LLM context windows.
  • Labels are fetched via schema:name with language filtering; IRI-valued dimensions fall back to the IRI itself if no label is found.
  • The search_datasets tool uses CONTAINS filters on schema:name and schema:description (the Stardog textMatch predicate is not supported on the public LINDAS endpoint).
  • In HTTP mode, each client session gets its own MCP server instance. Sessions are tracked via the Mcp-Session-Id header and cleaned up on disconnect.

License

MIT

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选