内容
# SIP 新闻 MCP 服务器,适用于卢森堡政府新闻
一个 [MCP](https://modelcontextprotocol.io) 连接器,允许 AI 助手**搜索和阅读卢森堡政府新闻发布服务的官方新闻**(Service information et presse, SIP),网址为 [`sip.gouvernement.lu`](https://sip.gouvernement.lu/de/actualites.html)。
它公开了完整的 SIP 新闻档案(新闻稿、公告、演讲、国家访问、部长新闻,约 2300 篇,追溯到 2000 年 2 月),以干净、结构化、全文可搜索的数据呈现,支持德语、法语或英语。
## 为什么存在
SIP 新闻页面通过 JavaScript 组件加载其列表,因此简单的 HTTP 获取请求会返回一个空壳。而这个连接器使用网站自己的 **RSS 端点**,返回干净的分页数据,新数据优先:
| 目的 | 端点 |
| --- | --- |
| 浏览所有新闻 | `GET /{lang}/actualites.rss?page={n}` |
| 全文搜索 | `GET /{lang}/support/recherche.rss?q={query}&page={n}` |
每个页面返回 50 个项目,作为整个档案的滑动窗口。连接器自动分页、去重、解码(双重编码)实体,从 URL 中恢复每个项目的类别、语言、日期,并按需获取完整文章正文。
## 工具
| 工具 | 功能 |
| --- | --- |
| `search_news` | 对整个档案进行关键词全文搜索(最新优先)。 |
| `semantic_search` | 基于语义(向量)搜索;处理自然语言问题。 |
| `browse_latest_news` | 按时间顺序排列的新闻提要,最新优先。 |
| `get_article` | 通过 URL 获取一篇文章的完整、清理后的文本。 |
| `list_categories` | 类别键和界面语言的参考列表。 |
| `build_semantic_index` | (重新)构建 `semantic_search` 使用的本地向量索引。 |
| `semantic_index_status` | 向量索引的大小和覆盖范围。 |
常见参数:
- `language` — `de`、`fr` 或 `en`(界面语言;许多项目为法语,因此如有需要,可尝试多种语言)。
- `limit` — 返回结果的数量;较大的值会深入历史记录。
- `since` / `until` — `YYYY-MM-DD` 日期范围。
- `category` — 例如 `communiques`(新闻稿)、`articles`、`discours`(演讲);参见 `list_categories`。
每个项目返回的字段:`title`、`summary`、`url`、`published`(ISO)、`published_human`、`category`、`category_label`、`content_language`、`source`。
`search_news` / `browse_latest_news` 还返回 `count`、`complete` 和可选的 `note`。`complete: false` 表示扫描在页面上限或时间预算处停止,而不是涵盖整个档案/范围,因此短列表或空列表不是权威的“无内容”(`note` 解释如何缩小查询范围)。`get_article` 返回正文和 `truncated` 标志。
## 语义搜索
`semantic_search` 根据**含义**而非精确关键词匹配新闻,因此它能回答自然语言问题(例如“与比利时的军事合作”、“对国家 IT 系统的攻击”),即使措辞与文章不同。
工作原理:
- `build_semantic_index` 遍历档案,为每个项目(标题 + 摘要)嵌入一个嵌入模型,并将向量存储在配置的向量存储中(默认为 **ChromaDB**)。对于 OpenRouter 上的 NVIDIA 检索模型,文档嵌入为 `passage`,查询嵌入为 `query`(非对称检索),这显著提高了排名。
- `semantic_search` 嵌入查询,并根据余弦相似度返回最近的项目,应用相同的 `language` / `category` / `since` / `until` 过滤器。每个结果都有一个 `[0, 1]` 区间内的 `similarity` 分数。
设置:
1. 获取 [OpenRouter API 密钥](https://openrouter.ai/keys),并将其放入服务器环境中,变量名为 `OPENROUTER_API_KEY`(参见下面的配置)。默认模型 `nvidia/llama-nemotron-embed-vl-1b-v2:free` 是免费的。(或者使用本地嵌入器,参见下文。)
2. 构建索引(从 Claude 调用 `build_semantic_index`,或运行以下一行命令)。完整构建涵盖整个档案(~2300 个项目,追溯到 2000 年),大约需要 1 分钟。定期重新运行以获取新新闻。
```powershell
uv run --extra semantic python -c "import asyncio; from sip_news_mcp.semantic import SemanticIndex; print(asyncio.run(SemanticIndex().build(language='fr', max_items=3000)))"
```
相关环境变量:
| 变量 | 用途 |
| --- | --- |
| `SIP_NEWS_SEMANTIC` | `on` / `off` / `auto`(默认为 `auto`)。关闭语义搜索以仅支持关键词搜索。 |
| `OPENROUTER_API_KEY` | 嵌入式 API 密钥(仅限默认 OpenRouter 提供商)。 |
| `SIP_NEWS_EMBED_MODEL` | 嵌入模型 ID(默认为免费的 Nemotron 模型)。 |
| `SIP_NEWS_EMBED_BASE_URL` | 嵌入式 API 基址;指向本地服务器以进行自托管嵌入。 |
| `SIP_NEWS_EMBED_API_KEY` | 嵌入密钥(回退到 `OPENROUTER_API_KEY`)。 |
| `SIP_NEWS_EMBED_INPUT_TYPE` | `on` / `off` / `auto` 非对称检索(默认为 `auto`)。 |
| `SIP_NEWS_VECTOR_BACKEND` | `chroma`(默认为)或 `qdrant`。 |
| `SIP_NEWS_CHROMA_DIR` | Chroma 索引位置;**仅限本地磁盘**(默认为 `%LOCALAPPDATA%` 下)。 |
参见 [.env.example](.env.example)。
#### 本地/自托管嵌入(Ollama,OpenAI兼容)
将 `SIP_NEWS_EMBED_BASE_URL` 指向任何 OpenAI 兼容的 `/embeddings` 服务器(Ollama,vLLM,LocalAI,text-embeddings-inference,...)。无需 OpenRouter 密钥。例如,使用 [Ollama](https://ollama.com)(`ollama pull nomic-embed-text`):
```bash
SIP_NEWS_EMBED_BASE_URL=http://localhost:11434/v1
SIP_NEWS_EMBED_MODEL=nomic-embed-text
# 无密钥;对于非 OpenRouter 端点,输入类型自动禁用
```
然后构建索引。(更改嵌入模型/端点会更改向量空间,因此使用 `refresh=true` 切换时需要重新构建索引。)
### 仅限关键词模式(无 RAG,最容易部署)
语义搜索是可选的。设置 `SIP_NEWS_SEMANTIC=off`(或简单地不安装向量后端),服务器仅公开四个关键词工具(`search_news`、`browse_latest_news`、`get_article`、`list_categories`)。无需向量数据库、无嵌入、无 OpenRouter 密钥以及无可选依赖项,使其成为最简单的部署方式。
向量数据库依赖项是**可选的额外功能**,因此基础安装非常轻量:
| 安装 | 功能 |
| --- | --- |
| `pip install .` | 仅限关键词(无向量依赖)。 |
| `pip install ".[chroma]"` | + 嵌入式 ChromaDB 后端。 |
| `pip install ".[qdrant]"` | + Qdrant 后端。 |
| `pip install ".[semantic]"` | + 两个后端。 |
默认情况下,`SIP_NEWS_SEMANTIC=auto` 服务器仅在配置的后端库实际安装时启用语义搜索。
## 要求
- [uv](https://docs.astral.sh/uv/)(推荐),或带有 `pip` 的 Python 3.10+。
`uv` 将自动下载合适的 Python;您不需要在系统范围内安装 Python。
> **注意(Windows + 网络驱动器)。** 如果您将此项目保留在网络/UNC 驱动器上,Python 的 Windows 扩展(`pywin32`,由 `mcp` 拉取)**无法从 UNC 路径加载其 DLL**,因此虚拟环境必须位于**本地磁盘**上。将 `UV_PROJECT_ENVIRONMENT` 指向本地文件夹(项目**代码**可以保留在网络驱动器上;仅安装的环境需要本地磁盘)。命令和 MCP 配置如下。
## 快速开始
```powershell
cd C:\path\to\SIP-MCP-Connector
$env:UV_PROJECT_ENVIRONMENT = "$env:LOCALAPPDATA\sip-news-mcp\venv"
uv sync --extra semantic --extra dev # 带有语义和测试依赖项的本地环境
uv run --extra dev pytest # 运行离线测试套件
uv run --extra semantic sip-news-mcp # 启动服务器(stdio,带有语义)
# 对于仅限关键词的服务器,删除额外的: uv run sip-news-mcp
```
使用同一 shell 进行快速实时检查,无需 MCP 客户端:
```powershell
uv run python -c "import asyncio; from sip_news_mcp.client import SipNewsClient; print(asyncio.run(SipNewsClient().search('cyber', language='de', limit=3)))"
```
## 从 Claude 使用
### Claude 桌面版
将以下内容添加到 `claude_desktop_config.json`
(Windows 上为 `%APPDATA%\Claude\claude_desktop_config.json`),然后重启 Claude 桌面版。参见 [`examples/claude_desktop_config.json`](examples/claude_desktop_config.json):
```json
{
"mcpServers": {
"sip-news": {
"command": "uv",
"args": ["--directory", "C:\\path\\to\\SIP-MCP-Connector", "run", "--extra", "semantic", "sip-news-mcp"],
"env": {
"UV_PROJECT_ENVIRONMENT": "C:\\sip-news-mcp\\venv",
"OPENROUTER_API_KEY": "sk-or-v1-...your key...",
"SIP_NEWS_CHROMA_DIR": "C:\\sip-news-mcp\\chroma"
}
}
}
}
```
(`--extra semantic` 和 `OPENROUTER_API_KEY` / `SIP_NEWS_CHROMA_DIR` 环境变量仅在需要语义搜索时需要;对于仅限关键词的服务器,请删除它们。如果 Claude 桌面版无法找到 `uv`,请使用 `uv.exe` 的绝对路径,因为它可能不会继承您的 shell `PATH`。)
### Claude 代码(CLI)
```powershell
claude mcp add sip-news `
--env UV_PROJECT_ENVIRONMENT="$env:LOCALAPPDATA\sip-news-mcp\venv" `
--env OPENROUTER_API_KEY="sk-or-v1-...your key..." `
-- uv --directory "C:\path\to\SIP-MCP-Connector" run --extra semantic sip-news-mcp
```
## 示例提示
- "在 SIP 中搜索 2025 年关于 *cybersécurité* 的新闻并总结前 5 篇。"
- "列出 2026-01-01 以来所有的 SIP 新闻稿(`communiques`)。"
- "查找提及 *armée* 的 SIP 文章并打开最新的完整版本。"
## 注意事项和限制
- 搜索使用 SIP 站点自己的全文引擎,这是一个广泛的匹配:命中可能只在正文中提及该术语,排名是站点的,而不是我们的。连接器忠实地返回这些结果。使用 `get_article` 在引用之前确认相关性。
- 内容语言因项目而异;连接器按结果报告 `content_language`,因此您可以区分法语和德语项目。
- 日期过滤对于最近的范围最有效(提要是最新优先的,并且一旦超过 `since` 就提前停止);非常旧的范围会深入分页并可能达到页面上限或 ~45 秒的时间预算,在这种情况下,结果标记为 `complete: false` 并附有解释性 `note`。
- 相同的请求在进程中缓存 5 分钟(有界 LRU),因此重复相同的查询不会重新命中服务器。单个搜索/浏览调用仍然发出多达 ~40 个顺序页面请求,但它们一次执行一个(每个 awaited 在下一个之前),在描述性 User-Agent 下,负载对公共政府服务器保持适中。
- `get_article` 仅获取 `https` URL on `sip.gouvernement.lu`(主机被解析和检查,不是子字符串匹配),因此不能转换为其他主机的请求。
- 此连接器仅读取公共页面;它不执行任何写入操作,因此不需要凭证。
## 部署(Docker / Kubernetes)
服务器支持两种传输方式,由 `MCP_TRANSPORT` 选择:
- `stdio`(默认)适用于 Claude 桌面版 / 代码(本地子进程)。
- `http`(streamable-http)适用于容器和 Kubernetes,监听 `MCP_HOST:MCP_PORT`(默认为 `0.0.0.0:8000`,路径 `/mcp`)。
它还通过 `SIP_NEWS_VECTOR_BACKEND` 支持两种向量后端:
- `chroma`(嵌入式,默认)适用于本地使用。
- `qdrant`(共享的网络 Qdrant)适用于容器/多个副本,设置为 `QDRANT_URL`(和可选的 `QDRANT_API_KEY`)。
### Docker Compose
启动 Qdrant + MCP 服务器(HTTP)一起:
```bash
echo "OPENROUTER_API_KEY=sk-or-v1-...your key..." > .env
docker compose up -d --build
docker compose run --rm index-build # 一次性填充向量索引
# MCP 服务器:http://localhost:8000/mcp (streamable-http)
```
### 最小/仅限关键词(无 RAG)
最简单的部署方式:无 Qdrant、无嵌入、无 API 密钥。仅限四个关键词工具。
```bash
docker compose -f docker-compose.minimal.yml up -d --build
# MCP 服务器位于 http://localhost:8000/mcp
```
最小镜像使用 `docker build --build-arg EXTRAS="" -t sip-news-mcp:minimal .` 构建并使用 `SIP_NEWS_SEMANTIC=off` 运行。
### Docker(仅镜像)
```bash
docker build -t sip-news-mcp:latest . # 完整(RAG)镜像
docker run --rm -p 8000:8000 \
-e OPENROUTER_API_KEY=sk-or-v1-... \
-e SIP_NEWS_VECTOR_BACKEND=qdrant -e QDRANT_URL=http://host.docker.internal:6333 \
sip-news-mcp:latest
```
### Kubernetes (Helm)
[`deploy/helm/sip-news-mcp`](deploy/helm/sip-news-mcp) 中的图表部署服务器、捆绑的 Qdrant(StatefulSet + PVC)、API 密钥的 Secret 和可选的安装后一次性 Job 以构建索引。
```bash
helm install sip-news deploy/helm/sip-news-mcp \
--set openrouter.apiKey=sk-or-v1-...your key...
# 或引用现有的 Secret: --set openrouter.existingSecret=my-secret
```
对于仅限关键词的部署(仅限 Deployment + Service,无 Qdrant、Secret 或 Job),设置 `semantic.enabled=false`:
```bash
helm install sip-news deploy/helm/sip-news-mcp --set semantic.enabled=false
```
关键值(参见 [`values.yaml`](deploy/helm/sip-news-mcp/values.yaml)):
| 值 | 默认值 | 用途 |
| --- | -------- | -------------------------------------------------- |
| `semantic.enabled` | `true` | 将 `false` 设置为仅限关键词服务器(无 Qdrant/密钥/作业)。 |
| `vector.backend` | `qdrant` | `qdrant` 或 `chroma`。 |
| `qdrant.enabled` | `true` | 部署捆绑的 Qdrant;将 `false` + `qdrant.url` 设置为外部 Qdrant。 |
| `openrouter.apiKey` | `""` | API 密钥(创建 Secret),或使用 `existingSecret`。 |
| `indexBuild.enabled` | `true` | 安装后运行一次性 Job 以填充索引(qdrant 后端)。 |
| `ingress.enabled` | `false` | 通过 Ingress 暴露。 |
| `replicaCount` | `1` | 扩展(qdrant 后端;保留 `1` 以使用 chroma)。 |
使用 `kubectl port-forward svc/sip-news-... 8000:8000` 访问它,然后将 MCP 客户端指向 `http://localhost:8000/mcp`。
### 通过 HTTP 连接 MCP 客户端
Claude 桌面版的配置仅限于stdio-only;要使用 HTTP 服务器,请配置支持 streamable-http 传输的 MCP 客户端,网址为 `http://<host>:8000/mcp`。### 部署(Docker / Kubernetes)
服务器支持两种传输方式,由 `MCP_TRANSPORT` 选择:
- `stdio`(默认)适用于 Claude 桌面版 / 代码(本地子进程)。
- `http`(streamable-http)适用于容器和 Kubernetes,监听 `MCP_HOST:MCP_PORT`(默认为 `0.0.0.0:8000`,路径 `/mcp`)。
它还通过 `SIP_NEWS_VECTOR_BACKEND` 支持两种向量后端:
- `chroma`(嵌入式,默认)适用于本地使用。
- `qdrant`(共享的网络 Qdrant)适用于容器/多个副本,设置为 `QDRANT_URL`(和可选的 `QDRANT_API_KEY`)。### 部署(Docker / Kubernetes)
服务器支持两种传输方式,由 `MCP_TRANSPORT` 选择:
- `stdio`(默认)适用于 Claude 桌面版 / 代码(本地子进程)。
- `http`(streamable-http)适用于容器和 Kubernetes,监听 `MCP_HOST:MCP_PORT`(默认为 `0.0.0.0:8000`,路径 `/mcp`)。
它还通过 `)
### 部署(Docker / Kubernetes)
服务器支持两种传输方式,由 `MCP_TRANSPORT` 选择:
- `stdio`(默认)适用于 Claude 桌面版 / 代码(本地子进程)。
- `http`(streamable-http)适用于容器和 Kubernetes,监听 `MCP_HOST:MCP_PORT`(默认为 `0.0.0.0:8000`,路径 `/mcp`)。
它还通过 `SIP_NEWS_VECTOR_BACKEND` 支持两种向量后端:
- `chroma`(嵌入式,默认)适用于本地使用。
- `qdrant`(共享的网络 Qdrant)适用于容器/多个副本,设置为 `QDRANT_URL`(和可选的 `QDRANT_API_KEY`)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器