mcpField
L
lindas-mcp

lindas-mcp

本地服务
github.com法律与政务05 周前更新

关于 lindas-mcp

lindas-mcp 是用于查询瑞士行政部门关联数据图谱 LINDAS 的 MCP 服务,面向处理统计数据立方体及相关公共数据的 Agent。它通过受限工具提供立方体结构和观测值,并将编码值解析为标签,而非依赖不受限的 SPARQL 查询。

主要功能

  1. 01搜索统计数据立方体
  2. 02查看维度、度量和许可证
  3. 03查询观测值并将编码解析为标签
  4. 04列出发布数据的联邦机构
  5. 05解析市镇名称、URI 和 BFS 编号
  6. 06运行受限的 SPARQL 查询

适用场景

  1. 01查找与主题相关的数据立方体
  2. 02读取带有人类可读标签的观测值
  3. 03查看立方体维度和许可证
  4. 04解析用于数据关联的市镇标识符

MCP 相关

向 MCP 客户端提供七种只读工具,用于搜索和查询 LINDAS 数据立方体、解析市镇信息及运行受限 SPARQL。原始 SPARQL 仅通过有上限的高级工具提供。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"malkreide-lindas": {
"command": "uvx",
"args": [
"lindas-mcp"
]
}
}
}
启动命令uvx lindas-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypilindas-mcp0.3.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

属于 Swiss Public Data MCP Portfolio — 一个开源 MCP 服务集合,连接 AI Agent 与瑞士公共及开放数据。 这是一个私人项目,与任何雇主或公共机构均无关联,未获其认可,也不代表其运营。

lindas-mcp

License: MIT Python 3.10+ MCP Data: LINDAS

LINDAS 的 MCP 服务 — 瑞士行政部门的关联数据知识图谱。

🇩🇪 德语版


LINDAS 是什么

LINDAS(Linked Data Service)是瑞士联邦的 SPARQL 知识图谱,由联邦档案馆运营。它不以表格形式发布数据,而是以 RDF 三元组形式发布:联邦各部门约 2000 个统计数据立方体(cube.link),以及为 visualize.admin.ch 提供支持的地理关联数据。

记忆口诀:「I14Y 是图书馆目录,LINDAS 就是图书馆本身。」 i14y-mcp 会告诉你某个数据集是否存在。 LINDAS 存储着数据,并让你一次查询其中的所有内容。

此服务将 LINDAS 封装为带防护的工具,而不是直接暴露原始 SPARQL,因为该存储需要精确查询,宽泛查询则会超时。


🎯 锚点演示查询

「当前适用的森林火灾危险等级是多少,由谁发布,依据哪种许可证?」

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"

返回的代码会以标签形式呈现 —「grosse Gefahr」,而不是 4。你可以使用 fedlex-mcp 解析许可证的 Fedlex URI。

演示

演示:Claude 使用 search_cubes、get_cube_structure 和 query_cube_observations


两阶段访问模式

LINDAS 立方体会自我描述,但其中的数据采用编码;此服务分两步读取:

  1. 结构 — 立方体的 SHACL 形状:其维度(可筛选的轴)、度量(数值),以及哪些维度包含代码列表。
  2. 数据 — 观测值,并根据该结构将编码值解析为人类可读的标签。

记忆口诀:「LINDAS 使用邮政编码,而非地名。」 一条观测记录会写着区域 1805;服务会为你将其转换为「Alpennordhang」。

这两个步骤都会在 query_cube_observations 中完成。 它会自行获取结构,因此调用方无需先调用 get_cube_structure 来获取可读的数据行 — 这样做只会重复查询立方体元数据和维度。get_cube_structure 用于了解立方体包含什么(维度名称、键还是度量、许可证),以及编写针对该立方体的 run_sparql 查询。它只会报告维度是否包含代码列表,不会列出其中的条目,因此也不能用于解码。


架构

                 ┌──────────────────────────────┐
                 │      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    │
                 └──────────────────────────────┘

lindas/ 包采用刻意分层的设计,因此可以原样移植到其他由 LINDAS 提供支持的服务中。client.py 只处理 HTTP 和 SPARQL;cube.py 只处理 cube.link 词汇;工具只依赖 cube.py。原始 SPARQL 不会传递给 Agent,只有通过带防护的 run_sparql 特殊通道时例外。

架构决策

架构 A(仅实时 SPARQL),并设有严格的词汇防护措施。

已于 2026-07-21 在线验证:

  • 端点稳定,无需身份验证;查询格式错误时会返回附带诊断信息的干净 HTTP 400 错误。
  • 盲目扫描(对整个存储执行 SELECT *、COUNT(*))会在 60–90 s 后超时;对同一问题加上 ?x a cube:Cube 限定后,约 2 s 即可得到答案。

工具中已落实以下限制:

  • 每个查询模板都以已知类为锚点,不进行无界扫描。
  • 强制采用两阶段访问;Agent 永远看不到原始代码。
  • run_sparql 的上限为 500 行和 30 s,并标记为高级工具。
  • 客户端超时设为 45 s,早于存储自身的 60–90 s 中止时间。

完整探测报告:docs/probe-lindas.md。


工具

工具用途
search_cubes按主题查找数据立方体。入口工具。对不同版本去重。
get_cube_structure第 1 阶段:维度、度量和许可证。
query_cube_observations第 2 阶段:数据点,并将代码解析为标签。
list_publishers发布数据立方体的联邦机构及其数量。
resolve_municipality名称 ↔ URI ↔ BFS 编号——组合数据集的关键字段。
run_sparql高级备用入口。设有上限和防护措施。
api_status检查可访问性并返回数据立方体数量。

所有工具均标注为 readOnlyHint: true。

阅读 search_cubes 结果

returned 表示返回结果的数量,而非现有结果的总数。以下两个字段说明答案的完整程度:

字段含义
truncatedfalse——cubes 中包含所有匹配项。true——还有更多匹配项,或可能还有更多,但服务器无法排除这种可能。
total_matched如果存在与 returned 采用相同单位的精确总数,则返回该总数;如果没有可比数字,则为 null。

得出结论前,请先检查 truncated。 如果值为 true,不要将结果报告为完整,也不要根据 returned 回答“有 N 个关于 X 的数据立方体”。按以下顺序扩大查询范围:提高 limit(最高为 100);如果达到 100 后仍被截断,则使用 list_publishers 中的 creator_uri 缩小范围,每次查询一个联邦机构;只有在确实需要版本历史时才使用 latest_only=False,因为这会扩大结果范围,而非避开截断。

total_matched 为 null 的情况比你想象的更常见,而且这是有意为之。 当 latest_only=true(默认值)时,LINDAS 能以较低成本计算的是数据立方体版本的数量,而工具返回的是合并版本后的数据立方体。2026-09-20 使用德语标签测得:「wald」匹配 127 个已发布版本,合并后为 35 个逻辑数据立方体;「energie」匹配 33 个版本,合并后为 13 个。若 returned 为 20 时 total_matched 显示 127,就会声称缺少 107 个数据立方体,而实际上最多只剩 15 个待查找。因此,该字段会显示 null,以提供准确结果,而不是提供一个不准确的数字。此时 truncated 仍然可靠,应以该字段为准。

服务器已获取所有匹配行时(这是常见情况,因为它会比所需数量多获取一行),两个分支中的 total_matched 都是精确值,而 truncated 根据该值计算,而非根据获取上限计算。


安装

uvx lindas-mcp
Claude Desktop
{
  "mcpServers": {
    "lindas": {
      "command": "uvx",
      "args": ["lindas-mcp"]
    }
  }
}
远程部署
LINDAS_MCP_TRANSPORT=streamable-http PORT=8000 lindas-mcp

LINDAS_MCP_TRANSPORT 接受 stdio(默认值)、streamable-http 或 sse。 传输方式决定路径:streamable-http 提供 /mcp,sse 提供 /sse。其他任何值都会回退到 stdio;它不会打开任何端口——在容器中,这只会表现为健康检查失败。 两种 HTTP 传输方式都会绑定到 HOST,默认值为 127.0.0.1; 若要公开访问(仅限位于反向代理之后),请显式设置 HOST=0.0.0.0。 LOG_LEVEL 用于调整 JSON 格式的 stderr 日志。

将其托管为远程连接器

连接器 URL 为 https://<host>/mcp。 路径不可配置—— 它由传输方式决定,而当前客户端预期使用 streamable-http。sse 及其 /sse 路径是规范中已被取代的传输方式;它们并未移除,仍可使用,但不应 将新的连接器指向这些路径。

托管部署——无论是 Railway、Fly,还是置于任何反向代理之后的容器——都需要 三个变量。第三个变量最容易在部署时被错误继承,因为缺少它时不会明显报错:

变量托管值未设置时
LINDAS_MCP_TRANSPORTstreamable-http回退到 stdio:进程会启动,但不会打开端口,只会表现为健康检查失败。容器镜像已设置此值。
HOST0.0.0.0仅绑定到环回地址,因此发布的端口无法访问任何内容。镜像有意设置了此值(SEC-016)。
LINDAS_MCP_ALLOWED_HOSTS公共主机名完全关闭 Host 验证——见下文。

LINDAS_MCP_ALLOWED_HOSTS 是以逗号分隔的主机名列表,不含协议和端口:lindas-mcp.example.ch,alias.example.ch,而不是 https://lindas-mcp.example.ch:443。系统会将该值与收到的 Host 标头进行 字面匹配;在 443 端口上通过 TLS 提供服务时,该标头不含端口。 系统会自动添加环回地址形式,因此容器健康检查仍可正常工作。

它可能在两个相反的方向上出错:

  • 在非环回地址上绑定但未设置:保护会完全关闭。 在这种情况下无法推导出主机名——服务器通过 本进程并不知晓的服务名称或公共 DNS 名称访问,而猜测的列表会导致每个真实请求都收到 421。 因此不会安装任何允许列表,也不会检查 Host 标头,这是 SDK 自身的默认行为。 唯一的迹象是启动警告 dns_rebinding_protection_off。
  • 设置了错误的名称:每个真实请求都会收到 HTTP 421。 匹配是精确的,并且会精确匹配端口—— mcp.example.ch 不包含 Host: mcp.example.ch:8443。如果代理转发的不是默认端口,请将两种形式都列出。

ALLOWED_ORIGINS 是另一项设置,仅涉及浏览器客户端。 它是以逗号分隔的 CORS 来源列表,未设置表示完全不允许浏览器客户端 ——这是默认行为。非浏览器客户端不会发送 Origin,因此不受影响。仍可使用 *,但会记录警告。如果确实提供浏览器访问,有一点值得注意:从 LINDAS_MCP_ALLOWED_HOSTS 派生的来源是 http://,因此必须自行将 https:// 浏览器来源添加到 ALLOWED_ORIGINS。

Docker
docker compose up --build          # binds 0.0.0.0 inside the container, publishes :8000

该镜像以非 root 用户运行,采用只读模式,设置了资源限制和 TCP 健康检查(参见 Dockerfile 和 compose.yaml)。


关联键

LINDAS 是一个连接器层,其中两个标识符使它能够与产品组合中的其他部分 组合使用:

键位置关联到
BFS 公社编号resolve_municipality → bfs_numberswiss-statistics-mcp,zurich-opendata-mcp
Fedlex URIcube 的 licence 字段fedlex-mcp

Fedlex 链接是个不太显眼的惊喜:许多 cube 会将其许可证声明为 法律依据 URI(fedlex.data.admin.ch/eli/cc/...),因此你可以从一个数据点 直接跳转到规范该数据的法律。


已知限制

已于 2026-07-21 在线验证。

  1. 宽泛的 SPARQL 查询会超时。 存储会在 60–90 s 后中止未锚定的扫描。 受保护的工具会避免此问题;run_sparql 会对此发出警告并限制运行时间。
  2. 观测值经过编码。 维度值是 URI,而不是标签。服务会通过各维度的代码列表解析这些值,但每个经过编码的维度都需要额外执行一次查询。设置 resolve_labels=False 可跳过解析。
  3. 无法在服务端按任意值筛选观测值。 LINDAS 无法以低成本在数据立方体内按维度值筛选观测值,因此 query_cube_observations 会读取前 N 条观测值。分析切片应使用 run_sparql。
  4. 各数据立方体的许可协议不尽相同,并以 dcterms:license 声明,通常是 Fedlex URI,而非纯文本名称。务必显示 licence 字段。
  5. 版本处理采用启发式方法。 search_cubes 会从数据立方体 URI 中去掉版本后缀,并在已发布的数据立方体中保留 schema:version 最高的版本,以此进行去重。形状特殊的 URI 可能无法正确合并;使用 latest_only=False 查看每个版本。total_matched 可能为 null,原因也在于此启发式方法:它是在 Python 中对 URI 形状的猜测,而 SPARQL 没有低成本的查询方式来表达这一结果,因此在查询中重述它,就会在第二处引入同一个可能发生偏差的猜测。

MCP 协议版本

此服务在同一端点上支持两个协议时代。客户端在连接上的第一个请求决定使用哪一个;之后若声称使用另一个时代的协议,则会被拒绝。

时代修订版使用方
initialize 握手2024-11-05 … 2025-11-25当前客户端使用的协议。服务会以请求指定的修订版作答;如果请求指定了更新的版本,则使用 2025-11-25 这一上限。
每请求信封2026-07-28携带 2026-07-28 _meta 信封的请求会建立现代连接。

这两个修订版均固定在 tests/test_protocol_version.py 中,并与已安装的 SDK 进行断言,因此 Dependabot 对 mcp 的升级不会在不知情的情况下更改其中任一版本。握手上限通过组装好的 ASGI 堆栈执行实时 initialize 测得,而不是从常量名称读取。

请注意,SDK 的 LATEST_PROTOCOL_VERSION 是现代时代的别名,而非握手时代的别名——如果只依据它固定版本,当前客户端实际协商的时代就仍可能悄然变化。

2026-07-28 在此处带来的变化

现代时代没有 initialize 握手,因此也没有能让客户端知道自己正在与谁通信的握手结果。我们明确处理了以下三项,不再依赖 SDK 的默认行为:

项目行为
serverInfo在每个响应的 _meta 和 server/discover 中写入信息。名称、标题、版本、描述和网站 URL 均从已安装发行版的元数据中解析,绝不手动填写。MCPServer 默认将 version 设为 "",且不会替换它,因此未设置的版本是一个没有实际信息的必填字段。
instructions由 server/discover 返回——这是现代客户端唯一的引导渠道。它会指出入口点,说明 query_cube_observations 会自行解析标签,并说明 get_cube_structure 的实际用途。
日志传递logging/setLevel 已移除(SEP-2577);客户端通过保留的 _meta 键 io.modelcontextprotocol/logLevel,按请求选择接收日志。未设置该键时,服务不发送任何内容;设置为 debug 时,服务会在该请求的流上,每次工具调用发送一条 notifications/message。
tools/list、server/discover携带 ttlMs 300000 和 cacheScope public(SEP-2549)。

所有内容都通过组装后的堆栈进行验证,见 tests/test_spec_2026_07_28.py——涵盖两个时代、 两种传输方式,以及日志选择加入的两个分支。工具契约则由 tool-definitions.lock.json(SEC-022)独立保障;同时,现代时代会断言仅提供其中 列出的工具,因此两个时代不会在同一个地址背后演变成两个不同的服务。

更新政策。 门禁失败时,不要盲目修改常量:请阅读两个修订版之间的规范变更日志,确认服务仍按预期运行,然后一并更新常量、本节、README.de.md 和 CHANGELOG.md。SDK 升级也需要经过审查,原因相同:任何影响协议的升级都会在 CHANGELOG.md 中注明。


测试

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 tests

实时测试必不可少:observationSet 间接关系(一组观测通过 cube:observationSet 隶属于一个立方体,而不是直接隶属于立方体)是一项结构性假设,无法通过模拟验证。实时测试会覆盖这一点。


贡献

请参阅 CONTRIBUTING.md,了解基本规则(只读、单一出口主机、锚定查询)和本地开发流程。更多内容: EXAMPLES.md 提供按受众分类的使用案例和工具选择表, docs/roadmap.md 介绍项目阶段, PUBLISHING.md 介绍 PyPI / MCP Registry 发布流程。


安全

请参阅 SECURITY.md,了解安全状况以及如何报告漏洞。


许可

MIT 许可证——请参阅 LICENSE。LINDAS 数据仍受各发布者为相应立方体声明的许可证约束。


作者

Hayal Oezkan · github.com/malkreide


致谢与相关项目

许可证:MIT。立方体数据仍受各发布者声明的许可证约束。


MCP Registry

MCP Registry 使用的所有权标记,用于将此 PyPI 包关联到 GitHub 命名空间:

mcp-name: io.github.malkreide/lindas-mcp

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。