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가 진실을 보유합니다. 벡터 인덱스는 단지 검색을 돕는 역할만 하며, 언제든지 삭제하고 재구축할 수 있습니다.
빠른 시작
로컬에서 약 5분이면 됩니다. 인터넷상의 모든 항목에 대해서는 먼저 서버에 배포를 읽어보세요.
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으로 로그인하세요.
어떤 포트도 공개되지 않으므로, 서비스에 접근하려면 리버스 프록시를 사용하거나, 임시로 ports: 매핑을 추가하여 테스트해보세요.
첫 번째 시작 시 수백 MB 크기의 임베딩 모델을 다운로드합니다. 인덱서는 준비될 때까지 재시도하므로, 첫 부팅 시 1~2분 동안 embeddings의 상태가 비정상으로 보이는 것은 정상입니다.
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에서 집계되고 캐시되므로, 새로고침 비용이 거의 없습니다.
서버에 배포
4GB 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 enableDocker를 설치한 후 배포를 소유할 사용자를 생성하세요:
sudo useradd --create-home --shell /bin/bash athena
sudo usermod -aG docker athena
sudo mkdir -p /srv/athena && sudo chown athena:athena /srv/athena컴포즈는 해당 사용자로 실행하고, 절대 sudo를 사용하지 마세요. 그렇지 않으면 바인드 마운트가 root 소유가 됩니다. docker 그룹의 구성원은 호스트의 root와 동등하므로, 그룹을 작게 유지하세요.
2. DNS
호스트를 가리키는 두 개의 A 레코드:
이름 | 제공 |
| Wiki.js 및 |
| 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.com4. 리버스 프록시
어떤 컨테이너도 포트를 공개하지 않습니다. 모든 것은 athena Docker 네트워크에 있으며, 프록시가 이 네트워크에 연결됩니다. 다음을 라우팅하세요:
호스트 | 대상 | 비고 |
|
| WebSocket 업그레이드, 100M 본문 제한 |
|
| |
|
| 버퍼링 금지, MCP 스트림 |
X-Forwarded-For를 전달하세요: 로그인은 주소별로 속도 제한이 있으며, 전달하지 않으면 모든 시도가 프록시에서 온 것으로 보입니다.
nginx를 athena 네트워크에 연결된 컨테이너로 실행하거나, 호스트에서 127.0.0.1에 바인딩된 ports: 매핑으로 실행하세요.
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 등록 | 아니요, 재구축 또는 재연결 |
| 아니요, 비밀번호 관리자에 사본 보관 |
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>는 복원하지 않고 백업을 다운로드하며, 각 덤프가 읽을 수 있는지 보고합니다.
검색 인덱스는 이후 자체 복구됩니다: 인덱서가 모든 페이지를 다시 읽고 내용이 변경된 항목을 다시 임베딩합니다.
설정
모든 것은 환경에서 가져옵니다. 각 서비스는 부팅 시 자체 설정을 검증하고 잘못된 항목 목록과 함께 종료되므로, 오타는 새벽 3시가 아니라 즉시 실패합니다.
다섯 가지 비밀, 모두 사용자가 생성합니다. Claude, OpenAI 또는 다른 회사의 자격 증명은 .env에 저장되지 않습니다.
비밀 | 보유 주체 | 보호 대상 |
| postgres, mcp, indexer | 전체 데이터베이스 접근 |
| mcp, indexer | Wiki.js API |
| mcp | MCP 엔드포인트 |
| dashboard | 대시보드 로그인 |
| dashboard, mcp, indexer | SELECT 전용 데이터베이스 역할 |
실행되는 서비스
서비스 | 포트 | 역할 |
| 내부 | Wiki.js 데이터, 활동 로그, pgvector를 통한 벡터 |
| 3000 | 읽고 편집하는 위키 |
| 내부 | 임베딩 모델, CPU에서 실행 |
| 8080 | AI가 연결하는 대상 |
| 8081 | 벡터 인덱스를 위키와 동기화 상태로 유지 |
| 8082 | 메트릭 |
| 없음 | 매시간 덤프, 확인, 푸시 |
별도의 벡터 데이터베이스는 없습니다. 벡터는 Postgres에 저장되므로, 하나의 백업으로 모든 것을 커버합니다.
ARM 호스트에서
embeddings이미지는linux/amd64용으로만 게시되므로 네이티브로 실행되지 않습니다.EMBEDDINGS_PROVIDER=openai를 Ollama와 같은 OpenAI 호환 엔드포인트로 지정하세요.
변수 | 기본값 | 설명 |
|
| 모든 바인드 마운트의 루트 디렉터리 |
|
| 로그인 페이지와 대시보드에 표시되는 이름 |
|
|
|
|
| 출처 스탬프 및 날짜 경로 |
|
| Wiki.js 데이터베이스 |
|
| 활동 로그 및 벡터, 자동 생성됨 |
|
| 콘텐츠 언어 |
|
| 대시보드 링크에 사용됨 |
| 필수 | 순수 https 출처, 경로 없음 |
|
| 대시보드 수치가 재사용되는 시간 |
|
| 변경 시 모든 항목 재색인 |
|
|
|
|
| 전체 동기화 간격 |
|
| 청크 크기 상한 |
|
| 일정, 보존 기간, 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회 시도 후 만료됩니다.
대시보드 세션은 만료 시간과 nonce가 포함된 서명된 쿠키이며, 토큰은 절대 포함되지 않습니다.
HttpOnly,SameSite=Strict이며, 교차 사이트 게시는 거부됩니다.비밀 비교는 일정 시간 내에 수행됩니다.
프록시 헤더는 루프백에서만 신뢰되므로, 원격 클라이언트가 주소를 위조하여 제한을 회피할 수 없습니다.
컨테이너는 루트가 아닌 사용자로 실행됩니다.
의도적으로 생략된 기능: 도구별 권한. 인증된 모든 클라이언트는 delete_page를 포함한 모든 도구를 호출할 수 있습니다. Wiki.js는 페이지 기록을 유지하므로 삭제는 복구 가능하지만, MCP_TOKEN을 위키에 대한 전체 쓰기 권한으로 취급하십시오. 또한 Athena는 단일 소유자를 가정합니다. Wiki.js에는 위키 읽기를 위한 자체 사용자가 있습니다.
MCP_TOKEN은 두 가지 방식으로 작동합니다. AI 클라이언트가 두 가지 방식으로 인증하기 때문입니다.
헤더 클라이언트(Cursor, Claude Desktop 등)는 Authorization: Bearer <MCP_TOKEN>을 전송합니다. 이것이 전체 메커니즘입니다.
브라우저의 Claude.ai는 그렇게 할 수 없습니다. 해당 사용자 지정 커넥터는 OAuth만 지원하며, MCP 사양은 동적 클라이언트 등록을 요구하므로, 브라우저 Claude를 수락하는 서버는 인증 서버가 되어야 합니다. Athena는 이를 구현합니다:
Claude가 자체 등록하고 생성된 클라이언트 ID를 받습니다. 사용자의 비밀은 관여하지 않습니다.
Claude가 사용자를 자체 서버의 로그인 페이지로 보냅니다.
사용자가 비밀번호로
MCP_TOKEN을 입력합니다. 이것이 사람의 승인 단계입니다.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회 실패 후 제한됨, 1분 기다리세요 |
시맨틱 검색 결과 없음 |
|
대시보드에 페이지가 뒤처져 표시됨 | 인덱서가 따라잡는 중임, 로그 확인 |
도구 호출이 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패키지 | 설명 |
| Wiki.js 클라이언트, 청킹, 검색 병합, 벡터, 인증, 설정 |
| MCP 서버, OAuth 인증 서버, 도구 |
| 동기화 루프, 임베딩, 벡터 쓰기, 내부 검색 API |
| 메트릭 인터페이스 |
| 백업 및 복원 컨테이너 |
| 단일 페이지 사이트 |
| 선택적 Wiki.js CSS 및 JS |
Bun은 TypeScript를 직접 실행하므로 빌드 단계가 없으며 컨테이너는 소스를 실행합니다. bun run --cwd packages/dashboard preview는 샘플 데이터로 preview.html을 생성합니다.
구성 방식:
인덱서는 증분 방식입니다. 각 페이지의 지문을 생성하고 변경되지 않은 항목은 건너뛰므로, 변경되지 않은 위키를 한 번 처리하는 데 비용이 들지 않습니다.
관리자 자격 증명이 있는 모든 서비스는 부팅 시 어드바이저리 락 아래에서 데이터베이스를 준비하므로 시작 순서는 중요하지 않습니다.
대시보드는 인라인 SVG 차트가 포함된 서버 렌더링 HTML입니다. 클라이언트 JavaScript, 차트 라이브러리, 빌드 단계가 없습니다.
웹사이트 게시. website/index.html은 해당 파일을 건드리는 모든 푸시에서 GitHub Pages에 배포됩니다. 먼저 수동으로 Pages를 한 번 활성화하십시오: Settings → Pages → Build and deployment → Source: GitHub Actions. 이는 자동화할 수 없습니다. Pages 사이트를 생성하려면 관리 권한이 있는 토큰이 필요하며 GITHUB_TOKEN에는 해당 권한이 없기 때문입니다.
라이선스
Apache-2.0. LICENSE를 참조하십시오.
This server cannot be installed
Maintenance
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
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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