使用说明
🌐 语言: 英语 | 韩语
🚀 RAG MCP服务器概述
RAG(检索增强生成)+MCP(模型上下文协议)服务器,自动将Outline wiki中的文档矢量化,以便AI代理(Claude Desktop等)可以运行 语义自然语言搜索 在他们身上。
它 共享自托管Outline堆栈的现有Redis 而不是旋转自己的,所以它下降与 一个Docker Compose文件 并且没有浪费资源。
✨ 主要特点
- 单容器部署(
outline-mcp-vector):FastAPI、Celery(Worker/Beat)和MCP服务器都在一个容器中运行,这使操作变得简单。 - 基础设施效率:重用Outline现有的Redis容器,隔离在自己的逻辑DB上(
db/1)所以这两条队伍永远不会相撞。 - 智能增量同步:实时webhooks和定期调度程序(默认情况下为每小时一次)协同工作,仅跟踪自上次以来更改或删除的文档
updated_at游标——每次运行时都不会完全重新嵌入。 - Gemini钥匙池:注册多个Gemini API密钥,它们被称为round-robin,当达到速率限制时自动故障转移(429)。
- MCP身份验证是选择Keycloak/OAuth:默认情况下,MCP服务器(流式HTTP)完全打开--set
MCP_OAUTH_ENABLED=true(加上发行者/资源/受众)要求使用Keycloak发行的Bearer JWT。此项目只充当OAuth资源服务器;它不会运行或配置Keycloak本身。
🛠 建筑
Outline Stack (existing infra) outline-net (shared network)
┌──────────────────────────────┐ │
│ [Outline] [Redis] │◄─────────────┼──────────────┐
└───────────────────▲──────────┘ │ │
│ (reuses logical DB /1) │ │
┌───────────────────┴─────────────────────────▼──────────────┼
│ outline-mcp-vector (1 Container Stack) │
│ - FastAPI (receives webhooks, responds immediately) │
│ - Celery Worker & Beat (background chunking/embedding/sched)│
│ - MCP Server (serves the search_knowledge tool over Streamable HTTP) │
└─────────────────────────────────────────────┬──────────────┘
│ (rag-net)
┌──────▼───────────────────────┐
│ Qdrant (internal vector DB) │
└──────────────────────────────┘
📦 3分钟快速入门
1.准备大纲并创建webhook
在启动RAG服务器之前,从Outline管理屏幕收集所需内容。
- 发布API密钥:在大纲中,转到 设置→ API令牌 并创建新令牌(
OUTLINE_API_KEY). - 注册一个webhook并获取其秘密首选 设置→ Webhooks→ 新建webhook,按如下方式注册,并复制 秘密 展示。
- 统一资源定位符:
http://<your-server-ip>:17000/webhook/outline(RAG服务器监听的地址) - 事件:选择
documents.create,documents.update,documents.delete - 将创建后显示的秘密字符串保存在安全的地方(
OUTLINE_WEBHOOK_SECRET).
2.检查Outline的Docker网络
为了让RAG服务器通过内部网络访问Outline和Redis容器,您现有的Outline docker-compose.yml 需要一个明确的外部网络名称(outline-net).
# Add this to your existing Outline docker-compose.yml if it's missing, then restart Outline
services:
outline:
networks: [outline-net]
redis:
networks: [outline-net]
networks:
outline-net:
name: outline-net
3.设置环境变量(.env)
创建一个 .env 将文件放入安装目录中,并填写步骤1中的值以及所需的设置。
# Outline integration (values gathered in step 1)
OUTLINE_API_KEY=ol_api_xxxxxxxxxxxx # Outline API token
OUTLINE_WEBHOOK_SECRET=your_secret_key # Secret copied from the Outline webhook screen
OUTLINE_API_URL=http://outline:3000 # Internal Docker-network URL
OUTLINE_PUBLIC_URL=https://wiki.domain.com # Public URL real users hit in their browser
# AI and vector DB settings
GOOGLE_API_KEYS=key1,key2,key3 # Gemini API keys (comma-separated for a round-robin pool)
QDRANT__SERVICE__API_KEY=strong_qdrant_key # Any string you like, used to authenticate to Qdrant
# DNS rebinding protection (Host/Origin header validation). Comma-separate your deployed
# domain(s); leave unset to keep this off (pre-existing behavior). Only relevant against
# malicious webpages attacking through a browser — non-browser clients (curl, Claude
# Desktop's remote connector) don't send an Origin header and aren't affected either way.
# MCP_ALLOWED_HOSTS=mcp.your-domain.com
# MCP_ALLOWED_ORIGINS=https://mcp.your-domain.com
# MCP auth — off by default (server is fully open). Set MCP_OAUTH_ENABLED=true and fill in
# the rest to require a Keycloak-issued Bearer JWT instead. This server is a Resource Server
# only; it validates against your Keycloak realm's JWKS, it doesn't run Keycloak itself
# (see docs/keycloak-reference-compose.yml for a throwaway realm to test against).
# MCP_OAUTH_ENABLED=true
# MCP_OAUTH_ISSUER_URL=https://keycloak.your-domain.com/realms/myrealm
# MCP_OAUTH_RESOURCE_URL=https://mcp.your-domain.com/mcp
# MCP_OAUTH_AUDIENCE=outline-mcp-client
请参阅MCP规范 授权指南 了解OAuth背后的概念 MCP_OAUTH_* 以上变量(资源服务器与授权服务器、受保护的资源元数据等)。
| 变量 | 必填? | 默认 | 备注 |
|---|---|---|---|
OUTLINE_API_KEY |
必需的 | - | 概述API令牌(设置→ API和应用程序 |
OUTLINE_WEBHOOK_SECRET |
必需的 | -- | 概述webhook签名密钥。如果留空,则完全跳过webhook签名验证——不建议 |
OUTLINE_BASE_URL |
必需的 | -- | 大纲的公共URL;也是退路 OUTLINE_API_URL/OUTLINE_PUBLIC_URL 在......下面 |
GOOGLE_API_KEYS |
必需的† | - | Comma-separated Gemini API密钥池,带故障转移的循环 |
QDRANT__SERVICE__API_KEY |
必需的 | -- | 任何字符串;也传递给Qdrant容器本身 service.api_key |
GEMINI_API_KEY |
可选 | -- | ¹如果不需要,可选择单键回退 GOOGLE_API_KEYS'泳池 |
OUTLINE_API_URL |
可选 | = OUTLINE_BASE_URL |
实际Outline API调用的内部Docker-network URL |
OUTLINE_PUBLIC_URL |
可选 | = OUTLINE_BASE_URL |
用于构建搜索结果中显示的文档链接的公共URL |
GEMINI_EMBEDDING_DIM |
可选 | 3072 |
输出向量维度 |
GEMINI_TIMEOUT_MS |
可选 | 30000 |
每个请求Gemini超时,毫秒 |
QDRANT_URL |
可选 | http://localhost:6333 |
|
QDRANT_TIMEOUT_SECONDS |
可选 | 10 |
按请求Qdrant超时,秒 |
MCP_HOST |
可选 | 0.0.0.0 |
|
MCP_PORT |
可选 | 8080 |
|
MCP_ALLOWED_HOSTS |
可选 | (空→ 保护关闭) | 用于DNS重新绑定保护的逗号分隔的主机允许列表 |
MCP_ALLOWED_ORIGINS |
可选 | (空) | 逗号分隔的Origin允许列表,相同的保护 |
MCP_OAUTH_ENABLED |
可选 | false |
打开Keycloak/OAuth承载令牌身份验证;服务器完全打开,同时 false |
MCP_OAUTH_ISSUER_URL |
如果需要 MCP_OAUTH_ENABLED=true |
-- | Keycloak领域颁发者URL |
MCP_OAUTH_RESOURCE_URL |
如果需要 MCP_OAUTH_ENABLED=true |
-- | 此服务器自己的外部URL,包括 /mcp 路径 |
MCP_OAUTH_AUDIENCE |
如果需要 MCP_OAUTH_ENABLED=true |
-- | 必须与 aud 声明您的Keycloak客户端问题 |
MCP_OAUTH_JWKS_URL |
可选 | {issuer}/protocol/openid-connect/certs |
仅当您的IdP不使用Keycloak的默认路径时才需要 |
REDIS_URL |
可选 | redis://redis:6379/1 |
共享Outline的Redis容器,逻辑DB 1 |
SYNC_INTERVAL_SECONDS |
可选 | 3600 |
Celery Beat的增量同步间隔 |
为设置Keycloak客户端 MCP_OAUTH_*: 在Keycloak管理控制台中,在您指向的领域上 MCP_OAUTH_ISSUER_URL at--
- 一个全新的领域没有自己的用户——领域创建向导不会要求用户
master您使用do登录控制台的realm管理员帐户 不 结转。如果有人会以交互方式登录这个领域(例如Claude基于浏览器的OAuth流,而不是纯粹的机器对机器)client_credentials设置),首先创建一个真实用户: 用户 → 创建新用户,然后该用户的 凭证 tab → 设置密码. - 客户 → 创建客户端 → 给它一个客户端ID(这与您要输入的值相同
MCP_OAUTH_AUDIENCE).如果此客户端将用于浏览器登录流,请同时启用 标准流程 在其“设置”选项卡上,并将调用者自己的OAuth回调添加到 有效的重定向URI (克劳德的https://claude.ai/api/mcp/auth_callback)--跳过此步骤,Keycloak只允许用户成功登录 然后 拒绝重定向回,这看起来像是登录失败,但实际上不是。 - 点击该客户端→ 客户端作用域 tab → 打开它
<client-id>-dedicated范围。 - 添加映射器 → 按配置 → 观众,然后设置 包括客户受众 对于同一个客户来说,这就是实际盖章的地方
aud索赔;如果没有它,发行的代币将携带Keycloak的默认值aud(account)相反,每个请求都失败了,签名相邻但受众与401不匹配。 - 保存,然后通过解码新发布的令牌(例如在jwt.io)并检查来确认它是否有效
aud实际上包含您的客户端ID——一个保存为空受众字段的映射器不会添加任何内容,这很容易被忽略。
还有一个特定的gotcha MCP_OAUTH_RESOURCE_URL:它必须是一个地址 客户 实际上可以访问——如果该客户端是克劳德,它正在Anthropic的云中运行,而不是在你的机器上。指向此 localhost 表示401响应 WWW-Authenticate 标头通告了一个无法访问的元数据URL,因此OAuth发现会自动失败。如果你正在对本地开发服务器(例如ngrok)进行隧道传输,这需要是隧道的实际公共HTTPS URL,每次自由层隧道重启时,它都会发生变化。另外,如果你在docker compose后面运行这个, docker compose restart 重用容器的原始环境,不会获取更新的环境 .env --使用 docker compose up -d 而是重新创建它。
4.运行Docker Compose
创建一个 docker-compose.yml 把下面的内容提出来。
version: '3.8'
services:
qdrant:
image: qdrant/qdrant:latest
expose:
- "6333"
environment:
- QDRANT__SERVICE__API_KEY
volumes:
- qdrant_data:/qdrant/storage
networks:
- rag-net
healthcheck:
test: ["CMD-SHELL", "bash -c 'echo -e \"GET /healthz HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\" > /dev/tcp/localhost/6333' || exit 1"]
interval: 10s
timeout: 5s
retries: 5
outline-mcp-vector:
image: sjw0066/outline-mcp-vector:latest
env_file: .env
environment:
- QDRANT_URL=http://qdrant:6333
- REDIS_URL=redis://redis:6379/1 # Shares Outline's Redis container (logical DB 1)
- MCP_HOST=0.0.0.0
- MCP_PORT=8080
ports:
- "17000:8000" # FastAPI port (webhook, sync)
- "17080:8080" # FastMCP Streamable HTTP port
volumes:
- sync_state:/data
networks:
- rag-net
- outline-net # Joins Outline's existing network
depends_on:
qdrant:
condition: service_healthy
networks:
rag-net:
driver: bridge
outline-net:
external: true # References the already-running Outline network
volumes:
qdrant_data:
sync_state:
docker compose up -d
💡 备注:容器启动后,它检测到Qdrant向量数据库为空,并自动拉入Outline的所有现有文档进行初始完全同步。
🔗 外部客户端设置指南(HTTPS/流式HTTP)
如何通过Nginx反向代理和家庭服务器域上的SSL证书从家庭服务器外的PC安全连接。
Nginx反向代理配置(必填)
因此,FastMCP的Streamable HTTP传输使用的流式响应不会被切断,请确保您的域 proxy_pass RAG服务器的块映射 港口 17080 并禁用代理缓冲。
server {
listen 443 ssl;
server_name mcp.your-domain.com;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
location / {
# ⭐ Key part: forward to the MCP port (17080) exposed by docker-compose.
proxy_pass http://localhost:17080;
# Required to keep the streaming connection alive in real time
proxy_buffering off;
proxy_cache off;
proxy_set_header Connection '';
chunked_transfer_encoding off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
2.克劳德桌面设置
默认情况下(MCP_OAUTH_ENABLED 未设置)MCP服务器处理任何请求,根本不进行身份验证检查——在VPN/专用网络后面很好,但任何直接到达URL的人都可以搜索你的知识库,所以如果可以从开放的互联网上访问,就把它放在某个东西后面(反向代理IP分配列表、VPN等)。在该模式下,只需将Claude Desktop指向URL:
{
"mcpServers": {
"outline-knowledge-base": {
"url": "https://mcp.your-domain.com/mcp"
}
}
}
如果你打开 MCP_OAUTH_ENABLED=true (Keycloak),添加连接器 高级设置→ OAuth客户端ID/OAuth客户端密码 填写Keycloak客户端的凭据,而不是将其留空。Claude Desktop在技术上可以发现服务器的OAuth元数据,并自行尝试动态客户端注册,但Keycloak的默认“受信任的主机”客户端注册策略拒绝来自它不知道的主机的匿名DCR——在实践中,无论哪种方式,你都需要一个预先注册的客户端,与下面的Claude Code设置相同(包括注册Claude的回调, https://claude.ai/api/mcp/auth_callback,作为a 有效的重定向URI 该客户)。一旦添加了凭据,第一个连接将引导您完成正常的浏览器登录/同意流程——没有静态令牌可以粘贴到配置中。看 docs/keycloak-reference-compose.yml 如果你想在本地测试,可以使用一次性Keycloak领域。无法运行基于浏览器的OAuth流的客户端可以直接将已颁发的Keycloak访问令牌作为 Authorization: Bearer <token> 头球
3.克劳德代码(CLI)设置
关闭OAuth后,像添加其他远程HTTP服务器一样添加它:
claude mcp add --transport http outline-knowledge-base https://mcp.your-domain.com/mcp
随着 MCP_OAUTH_ENABLED=true,跳过动态客户端注册,注册一个预配置的客户端——Keycloak的默认“受信任的主机”客户端注册策略拒绝来自它不知道的主机的匿名DCR(像ngrok这样的普通开发隧道会遇到这个问题),Claude Code自己的OAuth回调是一个本地环回URL(http://localhost:PORT/callback),与Claude Desktop的不同(https://claude.ai/api/mcp/auth_callback)--如果同时使用这两个,则都需要在同一Keycloak客户端上注册。
- 在Keycloak中,添加
http://localhost:8080/callback(或您在下面选择的任何端口)到该客户的 有效的重定向URI,以及已经存在的任何其他客户端的回调。 - 使用该客户端的凭据注册服务器:(提示输入密码;它存储在您的系统密钥链/凭据存储中,而不是
claude mcp add-json outline-knowledge-base \ '{"type":"http","url":"https://mcp.your-domain.com/mcp","oauth":{"clientId":"your-client-id","callbackPort":8080}}' \ --client-secret.mcp.json) claude mcp login outline-knowledge-base(或/mcp在会话内)通过浏览器登录运行。
⚙️ 手动同步和管理API
用于直接控制索引,超出后台自动同步(默认情况下每小时一次)。
- 触发增量同步:
POST http://localhost:17000/sync/outline - 强制进行全面重新索引:
POST http://localhost:17000/sync/outline?full=true - 检查同步状态:
GET http://localhost:17000/sync/status
如果这个开源项目对你有用,请用⭐️ 星!请在“问题”选项卡中留下任何问题。