Skip to main content
Glama

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 ──▶ Postgres

Wiki.js 持有真相。向量索引仅帮助查找内容,并且可以随时删除和重建。

快速上手

快速开始 · 连接你的AI

使用它

工具 · 仪表盘

实际部署

部署到服务器 · 备份

参考

配置 · 安全 · 运维 · 开发


快速开始

本地运行,大约五分钟。如果要在互联网上使用,请先阅读部署到服务器

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

然后:

  1. 打开 Wiki.js 并完成设置向导。

  2. 在 Wiki.js 中:管理 → API,启用它,创建一个令牌,并将其放入 .env 作为 WIKI_API_TOKEN

  3. 再次运行 docker compose up -d 以生效。

  4. 打开仪表盘并使用 DASHBOARD_TOKEN 登录。

没有暴露任何端口,因此需要通过反向代理访问服务,或者在尝试时临时添加 ports: 映射。

首次启动会下载一个几百 MB 的嵌入模型。索引器会重试直到模型就绪,因此首次启动时 embeddings 显示不健康一两分钟是正常的。


连接你的AI

所有内容都通过 MCP_PUBLIC_URL 提供,该 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" }
    }
  }
}

工具

工具

功能说明

search_knowledge

关键词和语义搜索,融合结果。每个结果都带有路径。

get_page

获取一个页面的完整 Markdown

get_page_structure

标题大纲,不含正文

append_to_page

在标题下追加内容,其余部分保持不变

create_page

创建新的 Markdown 页面

update_page

替换页面正文

move_page

移动或重命名

delete_page

删除页面,并从索引中移除

save_conversation

将对话归档到 conversations/YYYY/MM/ 目录下

capture_note

快速记录到 inbox/,稍后整理

list_pages

列出所有页面,包含路径和时间戳

get_wiki_stats

维基的大小、结构和陈旧程度,以便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
sudo mkdir -p /srv/athena && sudo chown athena:athena /srv/athena

以该用户身份运行 compose,切勿使用 sudo,否则绑定挂载的文件会归 root 所有。docker 组成员身份等同于主机上的 root 权限,因此请保持该组成员数量最小。

2. DNS

指向主机的两个 A 记录:

名称

服务

wiki.example.com

Wiki.js,以及 /dashboard/ 下的仪表盘

athena-mcp.example.com

MCP 端点

3. 配置

cd /srv/athena
git clone https://github.com/jannismilz/athena.git .
cp .env.example .env
chmod 600 .env        # it holds every secret

至少设置以下内容:

ATHENA_DATA_DIR=/srv/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.com

4. 反向代理

没有容器暴露端口。所有服务都位于 athena Docker 网络中,你的代理加入该网络。路由如下:

主机

目标

备注

wiki.example.com

wikijs:3000

WebSocket 升级,100M 请求体限制

wiki.example.com/dashboard/

dashboard:8082

athena-mcp.example.com

mcp:8080

必须不缓冲,MCP 流式传输

转发 X-Forwarded-For:登录按地址限流,没有它每次尝试看起来都来自代理。

将 nginx 作为容器运行,加入 athena 网络,如下所示,或者在主机上运行,并绑定 ports: 映射到 127.0.0.1

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。

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 注册信息

否,会重建或重新连接

.env

否,请在密码管理器中保留副本

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 远程,并将 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_PASSWORD

postgres, mcp, indexer

完全数据库访问

WIKI_API_TOKEN

mcp, indexer

Wiki.js API

MCP_TOKEN

mcp

MCP 端点

DASHBOARD_TOKEN

dashboard

仪表盘登录

DASHBOARD_DB_PASSWORD

dashboard, mcp, indexer

一个仅 SELECT 的数据库角色

运行的服务

服务

端口

说明

postgres

内部

Wiki.js 数据、活动日志和通过 pgvector 的向量

wikijs

3000

你阅读和编辑的维基

embeddings

内部

嵌入模型,运行在 CPU 上

mcp

8080

你的AI连接的对象

indexer

8081

保持向量索引与维基同步

dashboard

8082

指标

backup

每小时转储、验证、推送

没有单独的向量数据库。向量存储在 Postgres 中,因此一次备份覆盖所有内容。

在 ARM 主机上,嵌入镜像仅发布为 linux/amd64,无法原生运行。请将 EMBEDDINGS_PROVIDER=openai 指向 OpenAI 兼容的端点,例如 Ollama。

变量

默认值

说明

ATHENA_DATA_DIR

./data

所有绑定挂载的根目录

ATHENA_INSTANCE_NAME

Athena

显示在登录页面和仪表盘上

ATHENA_LOG_LEVEL

info

debug, info, warn, error

TZ

UTC

来源戳和日期路径

POSTGRES_DB

wiki

Wiki.js 数据库

ATHENA_DB

athena

活动日志和向量,自动创建

WIKI_LOCALE

en

内容语言

WIKI_PUBLIC_URL

http://localhost:3000

用于仪表盘链接

MCP_PUBLIC_URL

required

裸 https 起源,无路径

METRICS_CACHE_SECONDS

60

仪表盘数据重复使用的时间

EMBEDDINGS_MODEL

intfloat/multilingual-e5-small

更改将重新索引所有内容

EMBEDDINGS_PROVIDER

tei

tei,或 openai 用于兼容端点

INDEX_INTERVAL_SECONDS

300

完全协调间隔

CHUNK_MAX_CHARS

1200

块大小上限

BACKUP_*

.env.example

计划、保留、rclone 目标

更改 EMBEDDINGS_MODEL 会改变向量宽度,不同模型的向量无法比较,因此索引器会重建表并重新嵌入每个页面。Wiki.js 内容不受影响。


安全

每个容器只接收其使用的凭证。仪表盘既不获取 POSTGRES_PASSWORD 也不获取 WIKI_API_TOKEN,因此攻破它只能获得读取权限,别无其他。随时检查:

docker inspect athena-dashboard -f '{{range .Config.Env}}{{println .}}{{end}}' | grep -iE 'PASSWORD|TOKEN'
  • 未认证的 MCP 请求会返回 401 且无解释。

  • 两个登录路径在每地址失败 5 次后都会触发限流;登录链接在 3 次尝试后失效。

  • 仪表盘会话是携带过期时间和随机数的签名 cookie,绝不包含令牌。HttpOnlySameSite=Strict,跨站 POST 被拒绝。

  • 秘密比较是恒定时间的。

  • 代理头仅从回环地址信任,因此远程客户端无法伪造其地址以绕过限流。

  • 容器以非 root 用户运行。

故意缺失: 按工具权限。任何经过认证的客户端都可以调用所有工具,包括 delete_page。Wiki.js 保留页面历史记录,因此删除是可恢复的,但请将 MCP_TOKEN 视为对 wiki 的完全写入权限。Athena 也假定只有一个所有者;Wiki.js 有自己的用户用于阅读 wiki。

MCP_TOKEN 有两种工作方式,因为 AI 客户端以两种方式进行认证。

头客户端(如 Cursor 和 Claude Desktop)发送 Authorization: Bearer <MCP_TOKEN>。这就是整个机制。

浏览器中的 Claude.ai 无法做到这一点。它的自定义连接器仅支持 OAuth,并且 MCP 规范要求动态客户端注册,因此接受浏览器 Claude 的服务器必须成为授权服务器。Athena 实现了一个:

  1. Claude 注册自身并接收一个生成的客户端 ID。不涉及您的任何秘密。

  2. Claude 将您发送到您自己服务器上的一个登录页面。

  3. 您输入 MCP_TOKEN 作为密码。这是人工批准步骤。

  4. Athena 发放由 Athena 自身铸造的 Claude 令牌。

这些令牌写入 data/mcp/oauth-state.json绝不写入 .env。撤销它们:

rm data/mcp/oauth-state.json && docker compose restart mcp

如果您从不使用浏览器 Claude,请忽略所有这些。承载路径不会触及它。


操作

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

症状

原因

服务在启动时退出并列出配置

缺少必需变量或仍为 CHANGE_ME

Claude 无法连接,无登录页面

MCP_PUBLIC_URL 包含路径,或不是 https

登录拒绝正确的密码

5 次失败后触发限流,等待一分钟

无语义搜索结果

embeddings 仍在下载,检查其日志

仪表盘显示页面落后

索引器正在追赶,检查其日志

工具调用失败并返回 401

状态文件已清除或令牌已更改,重新连接客户端

Postgres 退出,"数据库文件不兼容"

现有数据下的镜像主要版本已更改

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

是什么

packages/core

Wiki.js 客户端、分块、搜索合并、向量、认证、配置

packages/mcp

MCP 服务器、OAuth 授权服务器、工具

packages/indexer

同步循环、嵌入、向量写入、内部搜索 API

packages/dashboard

指标界面

docker/backup

备份和恢复容器

website/

单页网站

themes/wikijs/

可选的 Wiki.js CSS 和 JS

Bun 直接运行 TypeScript,因此没有构建步骤,容器运行源代码。bun run --cwd packages/dashboard preview 会写入一个包含示例数据的 preview.html

各部分如何配合:

  • 索引器是增量的。它会对每个页面进行指纹识别,并跳过任何未更改的内容,因此对未修改的 wiki 进行一次遍历几乎没有成本。

  • 每个拥有管理员凭据的服务在启动时会在咨询锁下准备数据库,因此启动顺序无关紧要。

  • 仪表盘是服务器渲染的 HTML,包含内联 SVG 图表。无客户端 JavaScript、无图表库、无构建步骤。

发布网站。 website/index.html 在每次修改该文件的推送时部署到 GitHub Pages。首先手动启用 Pages 一次:设置 → 页面 → 构建和部署 → 来源:GitHub Actions。这无法自动化,因为创建 Pages 站点需要一个具有管理权限的令牌,而 GITHUB_TOKEN 没有这些权限。


许可证

Apache-2.0。参见 LICENSE

-
license - not tested
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.

  • Person-owned, portable AI memory as a remote MCP server, readable and writable by any MCP client.

  • An MCP server that gives your AI access to the source code and docs of all public github repos

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jannismilz/athena'

If you have feedback or need assistance with the MCP directory API, please join our Discord server