
I14y Mcp
io.github.malkreide由 GitHub 账号 malkreide 发布v0.4.0更新于 Oct 24, 2026
MCP server for I14Y — Switzerland's national open-data metadata catalogue (DCAT-AP-CH)
概览
让助手检索瑞士 I14Y 国家元数据目录,查明某个数据集由谁发布、通过哪个接口提供、依据何种许可。
- 可以做什么
- 围绕 I14Y 互操作平台(由联邦统计局维护的瑞士国家元数据目录)提供只读工具。工具包括目录全文检索、分页数据集清单、含分发渠道、下载地址与许可的完整数据集记录、已登记数据服务与公共服务清单、统一概念与代码表、带瑞士 UID 的发布机构、参与目录,以及 API 可达性检查。结果由 DCAT-AP-CH 映射为扁平记录,并附带来源与溯源信息。
- 适用场景
- 当助手需要先发现瑞士公共数据来源、再查询数据时使用:确定某主题的发布机构、接口或下载地址以及许可。它是目录与连接层,不是数据仓库,回答的是谁发布什么,而不是数据内容本身。
- 运行要求
- 以 stdio 本地进程运行,通过 uvx i14y-mcp 启动,需要 Python 与 uv;文档给出了 Claude Desktop 配置示例。也可通过 streamable HTTP 或 SSE 部署,涉及 I14Y_MCP_TRANSPORT、HOST、PORT、I14Y_MCP_ALLOWED_HOSTS 与 I14Y_MCP_CORS_ORIGINS。上游 API 经 HTTPS 调用,无需认证,未声明任何凭据。
安装
在 SourceWeft 中
- 打开 控制台中的 I14y Mcp,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
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.
i14y-mcp
[License: MIT] [Python 3.10+] [MCP] [Data: I14Y]
MCP server for the I14Y interoperability platform — Switzerland's national metadata catalogue.
Why this server exists
The other servers in this portfolio answer «what does the data say?». This one answers the question that comes first: «who publishes data on this topic, through which interface, under which licence?»
I14Y is the national data catalogue maintained by the Federal Statistical Office. It describes datasets, registered APIs, public services and harmonised concepts from the Confederation, cantons and communes, using the DCAT-AP-CH profile (eCH-0200).
Mnemonic: «Catalogue before shelf.» Without a catalogue, an agent has to already know a data source exists. With one, it can find it.
🎯 Anchor Demo Query
«Which authority publishes data on special needs education, through which interface is it available, and under which licence?»
Two tool calls turn a vague topic into a named authority, a download URL and a
licence you can act on — get_dataset aggregates the distributions, licences
and contact point into one record.
Demo
[Demo: Claude using search_catalog and get_dataset]
Architecture
Architecture decision
This server uses Architecture A (live API only).
Rationale (verified live on 2026-07-21):
- All read endpoints respond without authentication and paginate correctly.
- No bulk download of catalogue metadata is offered, and none is needed.
- Error responses follow RFC 7807, so failure modes are distinguishable.
Consequences:
- Every HTTP call retries transient failures with 2 s / 4 s / 8 s backoff.
search_catalogcaps results client-side because the upstream ignores paging.api_statusalways returns an evaluable state instead of empty records.
Full probe report: docs/probe-i14y.md.
Project phase
This server is in Phase 1 (read-only) of the portfolio's «Read-only First»
phase architecture: all tools are read-only, there is no authentication and no
personal data. See docs/roadmap.md for the phase model and
the prerequisites for any future write capability.
Tools
All tools are annotated readOnlyHint: true. Write operations exist in the
upstream API but are deliberately not exposed.
MCP primitives
This server exposes Tools only — no Resources, no Prompts. That is a deliberate choice, not an omission: I14Y is queried by free-text search and by opaque UUIDs, so there is no small, stable set of addressable URIs that would map cleanly onto MCP Resources, and the server ships no opinionated prompt templates. Every tool is read-only and idempotent; if a future stable entry point emerges (e.g. a fixed theme list) it is a candidate for a Resource.
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.
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.
What the server carries on the modern revision
2026-07-28 moves discovery off the initialize handshake onto
server/discover plus a per-request _meta envelope, and gives every cacheable
result a freshness hint. What this server puts on those surfaces is measured in
tests/test_spec_2026_07_28.py through the
assembled stack — and, for stdio, through a real subprocess — rather than read
back off the configuration:
The freshness hint is not cosmetic. With none set, the SDK answers ttlMs: 0, cacheScope: private — «already stale, never share» — for directories that are
fixed at import and cannot change while the process runs.
Both transports serve the modern revision: HTTP through the streamable-HTTP
session manager, and stdio — the default, and what uvx i14y-mcp starts —
through the same dual-era loop. Neither is evidence for the other, so both are
measured.
One thing this server advertises but does not use. On 2026-07-28 the
listChanged flags and resources.subscribe derive solely from whether
subscriptions/listen is served, and the SDK wires that handler
unconditionally. server/discover therefore reports listChanged: true for a
tool list that is fixed at import, and a subscribe capability over an empty
resource list; no change notification is ever sent. It is not switchable
through the public API — only a wholesale replacement of the server/discover
handler could do it, which would be a second truth about our own capabilities —
so it is pinned by a test instead of papered over.
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.
Installation
Or from source:
Claude Desktop
Remote deployment (Render, Railway)
I14Y_MCP_TRANSPORT accepts stdio (the default of the entry point itself),
streamable-http (http is a synonym) or sse. The HTTP transports bind to
HOST, which defaults to 127.0.0.1 (loopback); set HOST=0.0.0.0 to expose
the port on a PaaS (the container image already does both).
Connector URL: https://<host>/mcp
A Claude.ai custom connector speaks Streamable HTTP, and that transport serves
exactly one path: /mcp. sse is the older transport and serves /sse and
/messages instead — measured through the assembled app, POST /mcp answers
404 there and 200 under Streamable HTTP. The container image therefore
defaults to streamable-http; a connector pointed at an SSE deployment gets a
404 and never completes a handshake.
I14Y_MCP_ALLOWED_HOSTS — required for a public deployment
A comma-separated list of the hostnames the server is reached under — hostnames only, no scheme and no port:
The value is compared literally against the incoming Host header, so
https://i14y-mcp.up.railway.app or a trailing :443 matches nothing and every
request fails with HTTP 421 Invalid Host header. Behind TLS the browser
sends the bare hostname; a non-standard port needs the SDK's only wildcard form,
host:*. Loopback stays reachable either way, so container health checks are
unaffected.
Leaving it unset on a non-loopback bind does not fall back to something safe. The server cannot guess the name it will be addressed by, and a guessed list would reject every real request, so it switches the Host check off entirely and says so in the log:
railway.json
railway.json pins the one build setting the deployment cannot
get wrong on its own:
With any other builder Railway never looks at the Dockerfile. It derives a start
command itself, I14Y_MCP_TRANSPORT is then set nowhere, and main() falls into
the stdio branch — the container runs, never opens a port, and the only trace is
a failing health check. tests/test_entrypoint.py fails the day that setting
changes.
Two things the file deliberately does not carry:
- No environment variables. Railway's schema has no key for them at any
level, so
I14Y_MCP_ALLOWED_HOSTSandI14Y_MCP_TRANSPORTbelong in the service variables. The trap is that the schema validates values but waves invented keys through: a"variables": { … }block passes validation, your editor stays quiet, and Railway ignores it. A test rejects such a key. - No
healthcheckPath. Measured through the assembled app, no path answers a GET with 2xx:/and/healthare 404,/mcpis 400 without a session and 421 under a foreignHost. A health check pointed at any of them would mark the deployment unhealthy and roll it back. The Dockerfile's TCP check does the right thing instead. Should the server ever grow a real health route, the key may be set — a test then requires that the path actually answers.
CORS exposes the Mcp-Session-Id header so browser MCP clients keep their session.
Which browser origins may call the server comes from I14Y_MCP_CORS_ORIGINS, a
comma-separated list — unset means no browser client is permitted at all,
which is the default. * is still accepted and logs a warning. stdio and other
non-browser clients are unaffected either way.
Docker
The image is a hardened multi-stage build: it runs as a non-root user, ships no
build tools, and needs no secrets (the API is unauthenticated). See
Dockerfile and compose.yaml.
Join keys
I14Y is a connector layer. Two identifiers make it composable with the rest of the portfolio:
Known limitations
Verified live on 2026-07-21.
- The search index covers roughly half the register.
search_catalogreturns at most 1013 records;list_datasetsreaches about 2003. Uselist_datasetswhen completeness matters. - Search returns Datasets only. Filtering by
types=["Concept"]ortypes=["DataService"]yields zero results even though those entities exist. Uselist_conceptsandlist_data_servicesinstead. - The upstream ignores paging on search. The full result set is always
returned; this server caps it at 200 records and sets
truncated: true. - Licences vary per distribution, not per dataset. Most carry
«Opendata BY ASK», which requires attribution and restricts commercial use.
Always read the
licencefield before reuse. - Some metadata fields are simply empty. Frequency, temporal coverage and distribution format are optional and frequently unset by publishers. This is a data-quality property of the catalogue, not a bug in this server.
- Not every entry with an endpoint has a URL. Entries labelled only
«OpenAPI Spezifikation» without a URI are surfaced as
(no URI) <label>rather than dropped.
Testing
The live tests are not decoration: fundstück 4 in the probe report — keywords
nesting their language object under label — was caught by a live test after
the unit tests were already green.
Contributing
See CONTRIBUTING.md for the ground rules (read-only, one
egress host, no secrets) and the local dev loop. Maintainers: PUBLISHING.md
covers 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 catalogue data remains subject to the terms declared by each publisher.
Author
Hayal Oezkan · github.com/malkreide
Credits & related projects
- Data: I14Y Interoperability Platform, Federal Statistical Office (BFS)
- Standard: eCH-0200 / DCAT-AP-CH
- Source discovery inspired by rnckp/awesome-ogd-switzerland
- Portfolio: swiss-public-data-mcp
- Protocol: Model Context Protocol
Licence: MIT. The catalogue data remains subject to the terms declared by each publisher.
MCP Registry
Ownership marker used by the MCP Registry to link this PyPI package to the GitHub namespace:
来源:README.md,提交 b364841
工具
0版本历史
2- v0.4.0最新Sep 19, 2026
- v0.3.2Sep 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分