Athena MCP
Athena
一个你的 AI 可以写入、你也可以自行浏览的个人维基。
Athena 在 Wiki.js 前放置了一个 MCP 服务器。你的助手可以搜索维基、阅读页面,并将新内容归档:笔记、文档、完整的对话。它写下的所有内容都是普通的 Markdown 页面,你可以打开、编辑,并在任何特定模型消失后长久保存。
Claude / ChatGPT / Cursor
│ MCP over HTTPS
▼
athena-mcp ──── search ──▶ Wiki.js (keyword) + Postgres (meaning)
│ read ────▶ Wiki.js
└──────── write ───▶ Wiki.js ──▶ athena-indexer ──▶ PostgresWiki.js 保存着真实数据。向量索引仅用于辅助查找,可以随时删除并重建。
快速开始
本地运行,大约五分钟。如需部署到互联网,请先阅读部署到服务器。
git clone https://github.com/jannismilz/athena.git
cd athena
cp .env.example .env
$EDITOR .env # fill in every CHANGE_ME, one per secret:
# openssl rand -hex 32
docker compose up -d然后:
打开 Wiki.js 并完成设置向导。
在 Wiki.js 中:管理 → API,启用它,创建一个令牌,并将其放入
.env文件中的WIKI_API_TOKEN。再次运行
docker compose up -d以使其生效。打开仪表盘并使用
DASHBOARD_TOKEN登录。
数据写入到代码检出目录旁边的 data/ 目录,而非其内部,因此任何 git 操作都无法删除它。如需更改位置,请修改 ATHENA_DATA_DIR。
默认不开放任何端口,因此需要通过你的反向代理访问服务,或在试用时临时添加 ports: 映射。
首次启动会下载一个几百 MB 的嵌入模型。索引器会重试直到模型就绪,因此首次启动时 embeddings 显示不健康一两分钟是正常的。
Related MCP server: wiki-js-mcp
连接你的 AI
所有服务都通过 MCP_PUBLIC_URL 提供,该地址必须是一个裸的 https:// 源,不带路径。不要使用 /mcp。
Claude.ai → 设置 → 连接器 → 添加自定义连接器
URL:
https://athena-mcp.example.com/mcp客户端 ID 和密钥留空。Athena 会自行注册客户端。
浏览器页面会要求输入密码。这就是你的
MCP_TOKEN。
Cursor、Claude Desktop 和其他使用标头的客户端
{
"mcpServers": {
"athena": {
"url": "https://athena-mcp.example.com/mcp",
"headers": { "Authorization": "Bearer YOUR_MCP_TOKEN" }
}
}
}工具
工具 | 功能说明 |
| 关键词与语义搜索,结果融合。每条结果都带有路径。 |
| 获取一个页面的完整 Markdown 内容 |
| 获取标题大纲,不含正文 |
| 在某个标题下追加内容,其余部分保持不变 |
| 创建新的 Markdown 页面 |
| 替换页面正文 |
| 移动或重命名页面 |
| 删除页面,并从索引中移除 |
| 将对话归档到 |
| 快速记录到 |
| 列出所有页面,包含路径和时间戳 |
| 获取维基的大小、结构和陈旧程度,以便 AI 判断缺少什么 |
append_to_page 是最值得了解的工具:添加一个事实只需一个段落,无需重写整个页面。
为什么检索效果好。 精确术语命中 Wiki.js 全文索引,模糊问题命中向量索引,结果通过倒数排序融合(reciprocal rank fusion)合并,确保任一来源都不会被埋没。文本块会记录其上方标题,因此返回的内容保留了上下文。助手访问的每个页面都会标记是哪个助手在何时访问的,这些信息来自经过身份验证的客户端,而非模型自称的信息。
仪表盘
独立服务,运行在 8082 端口。使用 DASHBOARD_TOKEN 登录;URL 中不包含任何令牌。对于脚本,请使用 Bearer 标头:
curl -H "Authorization: Bearer $DASHBOARD_TOKEN" \
https://wiki.example.com/dashboard/api/metrics?days=30面板 | 功能说明 |
内容 | 页面数、字数、按区域统计、最大页面、即将过期的页面 |
AI 活动 | 每日调用次数、使用的工具、使用的助手、读取 vs 写入 |
未找到结果的搜索 | 你的维基无法回答的内容 |
索引健康 | 存储的块数、已索引的页面数、落后程度 |
备份 | 上次运行完成时间、大小、存储位置 |
第三行是最有价值的面板。每条记录都值得写成一个页面。
它双重只读:从不写入,并且以 athena_readonly 角色连接 Postgres,该角色仅拥有 SELECT 权限。数据在 Postgres 中聚合并缓存,因此刷新几乎不消耗资源。
部署到服务器
一台 4 GB 的 VPS 即可运行所有服务,包括在 CPU 上运行的嵌入模型。
1. 主机与防火墙
sudo ufw default deny incoming && sudo ufw default allow outgoing
sudo ufw allow 22/tcp && sudo ufw allow 80/tcp && sudo ufw allow 443/tcp
sudo ufw enable安装 Docker,然后创建一个拥有部署权限的用户:
sudo useradd --create-home --shell /bin/bash athena
sudo usermod -aG docker athena以该用户身份运行 Compose,切勿使用 sudo,否则绑定挂载的文件将归 root 所有。docker 组成员身份等同于主机上的 root 权限,因此请严格控制成员数量。
2. DNS
指向主机的两条 A 记录:
名称 | 服务内容 |
| Wiki.js,以及 |
| MCP 端点 |
3. 布局与配置
Athena 写入的所有内容都通过一个设置 ATHENA_DATA_DIR 控制,因此整个安装可以位于单个目录下。使用两个具有不同生命周期的子目录:
/athena
├── app/ the git repository replaceable, thrown away on every upgrade
└── data/ postgres, state, irreplaceable, never touched by git
uploads, backups它们是同级目录,而非嵌套,这正是关键所在。data/ 在 .gitignore 中,而 git clean -xdf 会删除被忽略的文件,因此检出目录内的数据可能因一个常规命令而被删除,且无确认和撤销操作。同级目录则无法被任何 git 操作触及。
默认的 ATHENA_DATA_DIR=../data 会自动为你提供此布局,因此无需记忆。
sudo mkdir -p /athena && sudo chown athena:athena /athena
cd /athena
git clone https://github.com/jannismilz/athena.git app
cd app
cp .env.example .env
chmod 600 .env # it holds every secretATHENA_DATA_DIR 默认为 ../data,该路径相对于存放 Compose 文件的目录解析。如上所述克隆到 /athena/app,数据将自动落入 /athena/data,无需额外配置。设置密钥:
POSTGRES_PASSWORD=...
MCP_TOKEN=...
DASHBOARD_TOKEN=...
DASHBOARD_DB_PASSWORD=...
MCP_PUBLIC_URL=https://athena-mcp.example.com
WIKI_PUBLIC_URL=https://wiki.example.comCompose 会在首次启动时创建 /athena/data 及其子目录。所有 docker compose 命令都从 /athena/app 目录运行。
/athena/data
├── postgres/ the wiki, users, settings, uploads, activity log, vectors
├── wikijs/ Wiki.js config, cache, upload cache
├── mcp/ oauth-state.json, the tokens issued to AI clients
├── indexer/ index bookkeeping, rebuilt automatically if lost
├── embeddings/ the downloaded model
└── backups/ local dumps plus status.json只有 postgres/ 是不可替代的,备份容器会每小时转储它。其他所有内容要么自动重新生成,要么只需重新连接一次。
如果你更倾向于遵循文件系统层次结构标准,可以将数据放在 /srv/athena,将代码检出放在 /opt/athena。对于只做一项工作的机器,上述单根布局更简单,两种方式都可行:仅由 ATHENA_DATA_DIR 决定。
4. 反向代理
没有容器开放端口。服务位于两个网络上:
athena,内部网络。Postgres、嵌入模型和索引器仅在此网络中,因此即使代理被攻破也无法访问数据库。athena-edge,你的反向代理加入的网络。只有以下三个服务在此网络中。
路由配置如下:
主机 | 目标地址 | 备注 |
|
| WebSocket 升级,100M 请求体限制 |
|
| |
|
| 不得缓冲,MCP 流式传输 |
转发 X-Forwarded-For:登录功能按地址限流,没有此标头,所有尝试看起来都来自代理。
如下所示,将 nginx 作为容器运行并加入 athena-edge 网络,或者在主机上运行并绑定 127.0.0.1 的 ports: 映射。加入边缘网络意味着代理可以访问 Wiki.js、MCP 服务器和仪表盘,而无法访问其他任何内容。
server {
listen 80;
server_name wiki.example.com;
location / {
proxy_pass http://wikijs:3000;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
client_max_body_size 100M;
proxy_read_timeout 120s;
}
location /dashboard/ {
proxy_pass http://dashboard:8082/;
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;
}
}
server {
listen 80;
server_name athena-mcp.example.com;
location / {
proxy_pass http://mcp:8080;
proxy_http_version 1.1;
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;
# MCP streams responses. Without these, long tool calls appear to hang.
proxy_set_header Connection "";
proxy_buffering off;
proxy_cache off;
proxy_read_timeout 300s;
}
}然后使用 certbot 颁发证书,或在你已有的任何地方终止 TLS。
这里没有特定于平台的内容。一个运行 Compose 并提供自身代理的 PaaS 需要三个设置,全部在 .env 中:
ATHENA_DATA_DIR=../files # Dokploy's persistent directory
ATHENA_EDGE_NETWORK=dokploy-network
ATHENA_EDGE_EXTERNAL=trueATHENA_DATA_DIR 最为重要:Dokploy 会在重新部署时清理绝对绑定挂载路径,因此使用绝对路径会破坏数据库。相对于应用目录的路径则可以保留。
然后在平台 UI 中添加域名,指向服务及其端口:
域名 | 服务 | 端口 |
|
| 3000 |
|
| 8080 |
|
| 8082 |
平台会生成自己的路由标签并处理 TLS,因此完全跳过 nginx 部分。其他所有内容,包括 Compose 文件,保持不变。
你无需将镜像发布到仓库:Dokploy 会从仓库构建。构建四个镜像确实会与 Postgres 和嵌入模型争夺内存,因此在小型主机上,你可能更倾向于在 CI 中构建并拉取镜像。
5. 启动,然后锁定维基
docker compose up -d && docker compose ps立即完成 Wiki.js 向导。否则,任何找到该主机的人都可以认领管理员账户。然后,在 Wiki.js 中:
用户组 → 访客:移除读取权限,除非你希望维基公开。
认证:关闭自助注册。
API:启用它并创建
WIKI_API_TOKEN所需的令牌。
6. 验证
curl -s https://athena-mcp.example.com/health
# Must reject unauthenticated calls:
curl -s -o /dev/null -w '%{http_code}\n' -X POST https://athena-mcp.example.com/mcp
# expected: 401备份
一次 pg_dump 就是完整的备份。 Wiki.js 将页面、历史记录、用户、权限、设置以及所有上传文件的字节都存储在 Postgres 中。上传文件存储在 assetData 表中;data/wikijs/uploads 下的文件只是缓存。Athena 的活动日志和搜索向量存储在同一个服务器上的第二个数据库中。
数据 | 备份中是否包含 |
页面、历史记录、用户、设置 | 是 |
上传的图片和文件 | 是 |
活动日志和搜索向量 | 是 |
索引簿记、OAuth 注册信息 | 否,会重建或重新连接 |
| 否,请在密码管理器中保留副本 |
backup 容器每小时运行一次。每次运行会转储两个数据库,检查每个转储文件是否可读,保留本地副本,推送到你的 rclone 目标,验证上传是否匹配,然后才进行清理。失败的运行永远不会删除你最后一个良好的备份。
docker compose run --rm backup now # take one now
docker compose run --rm backup restore list # see what exists
docker compose logs -f backup # watch the schedule完全在 .env 中配置。任何 rclone 目标都适用:S3、Backblaze、Wasabi、MinIO、Hetzner。将 BACKUP_REMOTE 留空则仅将备份保留在宿主机上。
添加一个 crypt remote 并将 BACKUP_REMOTE 指向它。这样目标端只会收到密文,包括文件名。
BACKUP_REMOTE=crypt:
RCLONE_CONFIG_CRYPT_TYPE=crypt
RCLONE_CONFIG_CRYPT_REMOTE=s3:my-bucket/athena
RCLONE_CONFIG_CRYPT_PASSWORD=<rclone obscure ...>
RCLONE_CONFIG_CRYPT_PASSWORD2=<rclone obscure ...>将两个密码都保存在你的密码管理器中。没有它们,备份将无法读取,包括你自己也无法读取。
恢复
在需要之前练习这个操作。没有人运行过的恢复操作只是猜测。
docker compose run --rm backup restore list
docker compose stop wikijs mcp indexer dashboard
docker compose run --rm backup restore run 2026-08-18T115529Z
docker compose start wikijs mcp indexer dashboard它会要求你输入数据库名称以确认。restore fetch <stamp> 会下载备份而不恢复它,并报告每个转储文件是否可读。
搜索索引会在之后自行修复:索引器会重新读取每个页面,并重新嵌入内容发生变化的任何内容。
配置
所有内容都来自环境变量。每个服务在启动时都会验证自己的配置,如果出现问题则会退出并列出错误信息,这样拼写错误会立即失败,而不是在凌晨三点才暴露问题。
五个密钥,全部由你生成。Claude、OpenAI 或任何其他人的凭证永远不会存储在 .env 中。
密钥 | 持有者 | 保护对象 |
| postgres, mcp, indexer | 完全数据库访问权限 |
| mcp, indexer | Wiki.js API |
| mcp | MCP 端点 |
| dashboard | 仪表盘登录 |
| dashboard, mcp, indexer | 一个仅具有 SELECT 权限的数据库角色 |
运行的服务
服务 | 端口 | 说明 |
| 内部 | Wiki.js 数据、活动日志以及通过 pgvector 存储的向量 |
| 3000 | 你阅读和编辑的 Wiki |
| 内部 | 嵌入模型,运行在 CPU 上 |
| 8080 | 你的 AI 连接的对象 |
| 8081 | 保持向量索引与 Wiki 同步 |
| 8082 | 指标 |
| 无 | 每小时转储、验证、推送 |
没有单独的向量数据库。向量存储在 Postgres 中,因此一个备份即可覆盖所有内容。
在 ARM 宿主机上,嵌入镜像仅发布为
linux/amd64版本,无法原生运行。请将EMBEDDINGS_PROVIDER=openai指向一个兼容 OpenAI 的端点,例如 Ollama。
变量 | 默认值 | 说明 |
|
| 所有绑定挂载的根目录,是检出目录的同级目录 |
|
| 显示在登录页面和仪表盘上 |
|
| 你的反向代理加入的网络 |
|
| 当平台提供该网络时设为 |
|
|
|
|
| 来源时间戳和带日期的路径 |
|
| Wiki.js 数据库 |
|
| 活动日志和向量,自动创建 |
|
| 内容语言 |
|
| 用于仪表盘链接 |
| 必需 | 纯 HTTPS 源,无路径 |
|
| 仪表盘数据重复使用的时长 |
|
| 更改它会重新索引所有内容 |
|
|
|
|
| 完全重新协调的间隔 |
|
| 块大小上限 |
| 参见 | 计划、保留策略、rclone 目标 |
更改 EMBEDDINGS_MODEL 会改变向量宽度,并且来自两个模型的向量无法比较,因此索引器会重建表并重新嵌入每个页面。Wiki.js 内容不受影响。
安全
每个容器只接收它使用的凭证。仪表盘既不会获得 POSTGRES_PASSWORD 也不会获得 WIKI_API_TOKEN,因此攻破它只能获得读取权限,仅此而已。随时检查:
docker compose exec dashboard env | grep -iE 'PASSWORD|TOKEN'未经身份验证的 MCP 请求会收到 401 且无任何说明。
两个登录路径在每地址 5 次失败后都会触发限流;登录链接在 3 次尝试后失效。
仪表盘会话是带有过期时间和随机数的签名 Cookie,绝不包含令牌。
HttpOnly、SameSite=Strict,并且拒绝跨站 POST 请求。密钥比较是恒定时间的。
代理头仅信任来自回环地址的请求,因此远程客户端无法伪造其地址以绕过限流。
容器以非 root 用户运行。
故意缺失: 按工具的权限。任何经过身份验证的客户端都可以调用所有工具,包括 delete_page。Wiki.js 保留页面历史记录,因此删除操作是可恢复的,但请将 MCP_TOKEN 视为对你 Wiki 的完全写入权限。Athena 也假设只有一个所有者;Wiki.js 有自己的用户用于阅读 Wiki。
MCP_TOKEN 有两种工作方式,因为 AI 客户端有两种身份验证方式。
Header 客户端,例如 Cursor 和 Claude Desktop,发送 Authorization: Bearer <MCP_TOKEN>。这就是整个机制。
浏览器中的 Claude.ai 无法做到这一点。其自定义连接器仅支持 OAuth,并且 MCP 规范要求动态客户端注册,因此接受浏览器 Claude 的服务器必须是一个授权服务器。Athena 实现了一个:
Claude 注册自身并收到一个生成的客户端 ID。不涉及你的任何秘密。
Claude 将你发送到你自己的服务器上的一个登录页面。
你输入
MCP_TOKEN作为密码。这是人工批准步骤。Athena 颁发由 Athena 自身生成的 Claude 令牌。
这些令牌被写入 data/mcp/oauth-state.json,绝不会写入 .env。使用以下命令撤销它们:
rm data/mcp/oauth-state.json && docker compose restart mcp如果你从不使用浏览器 Claude,请忽略所有这些。Bearer 路径不涉及它。
操作
docker compose logs -f mcp
curl -s localhost:8081/stats | python3 -m json.tool
# Force a full reconciliation
docker compose exec -T indexer bun -e 'await fetch("http://127.0.0.1:8081/sync",{method:"POST"})'升级。 始终先备份:Wiki.js 在启动时会运行自己的迁移,而这些迁移无法通过停止容器来逆转。
docker compose run --rm backup now
git pull && docker compose build && docker compose up -d症状 | 原因 |
服务在启动时退出并列出配置 | 缺少必需的变量或变量值仍为 |
Claude 无法连接,无登录页面 |
|
登录拒绝正确的密码 | 5 次失败后触发限流,等待一分钟 |
无语义搜索结果 |
|
仪表盘显示页面落后 | 索引器正在追赶,检查其日志 |
工具调用失败并返回 401 | 状态文件被清除或令牌已更改,重新连接客户端 |
Postgres 退出,显示 "database files are incompatible" | 镜像主版本在现有数据下发生了更改 |
Postgres 无法读取由不同主版本写入的数据目录。转储、清除、恢复:
docker compose run --rm backup now # on the OLD version
docker compose down
mv data/postgres data/postgres.old # keep until you are happy
# edit the image tag in docker-compose.yml and the FROM line in
# docker/backup/Dockerfile to the same new major version
docker compose build backup
docker compose up -d postgres
docker compose run --rm backup restore run <stamp> # once per database
docker compose up -d向量索引会与所有其他内容一起恢复,因此无需重新嵌入任何内容。
开发
bun install
bun test # 145 tests
bun run check # typecheck, lint, test包 | 说明 |
| Wiki.js 客户端、分块、搜索合并、向量、身份验证、配置 |
| MCP 服务器、OAuth 授权服务器、工具 |
| 同步循环、嵌入、向量写入、内部搜索 API |
| 指标接口 |
| 备份和恢复容器 |
| 单页网站 |
| 可选的 Wiki.js CSS 和 JS |
Bun 直接运行 TypeScript,因此没有构建步骤,容器直接运行源代码。bun run --cwd packages/dashboard preview 会生成一个包含示例数据的 preview.html。
各部分如何协同工作:
索引器是增量的。它会对每个页面进行指纹识别,并跳过任何未更改的页面,因此对未修改的 Wiki 进行一次遍历不会产生任何成本。
每个拥有管理员凭证的服务在启动时,会在一个咨询锁下准备数据库,因此启动顺序无关紧要。
仪表盘是服务器端渲染的 HTML,包含内联 SVG 图表。没有客户端 JavaScript,没有图表库,没有构建步骤。
发布网站。 website/index.html 会在每次有推送触及它时部署到 GitHub Pages。首先需要手动启用一次 Pages:设置 → Pages → 构建和部署 → 源:GitHub Actions。这无法自动化,因为创建 Pages 站点需要一个具有管理权限的令牌,而 GITHUB_TOKEN 没有此权限。
许可证
Apache-2.0。参见 LICENSE。
This server cannot be deployed
Maintenance
Related MCP Connectors
Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.
Hosted markdown project wikis your team's AI assistants read, search, and update over MCP.
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
One memory, every AI. A shared, user-owned markdown memory your AI clients read and write over MCP.
Related MCP Servers
- AlicenseAqualityCmaintenanceAn MCP server that enables AI agents to interact with Wiki.js as a knowledge base through a comprehensive set of 29 tools for content retrieval and management. It supports full-text search, page versioning, and asset browsing with optional write operations secured by safety gates.2928 npm8MIT
- AlicenseAqualityDmaintenanceAn MCP server for Wiki.js that enables AI agents to create, read, update, search, list, and move wiki pages via the GraphQL API. It supports surgical section updates and structured content management through named sections.6MIT
- AlicenseAqualityCmaintenanceAn MCP server that enables AI agents to compile, refine, and interlink knowledge into a persistent wiki, replacing RAG with structured, curated knowledge.1528 npm3MIT
- AlicenseNot gradedqualityCmaintenanceMCP server for Wiki.js integration, enabling AI assistants to create, read, update, delete, search, and move wiki pages via natural language.1MIT