Athena MCP
Athena
Ein persönliches Wiki, das Ihre KI schreibt und das Sie selbst durchsuchen können.
Athena stellt einen MCP-Server vor Wiki.js bereit. Ihr Assistent durchsucht das Wiki, liest Seiten und legt neue an: Notizen, Dokumentationen, ganze Gespräche. Alles, was er schreibt, ist eine gewöhnliche Markdown-Seite, die Sie öffnen, bearbeiten und behalten können, lange nachdem ein bestimmtes Modell verschwunden ist.
Claude / ChatGPT / Cursor
│ MCP over HTTPS
▼
athena-mcp ──── search ──▶ Wiki.js (keyword) + Postgres (meaning)
│ read ────▶ Wiki.js
└──────── write ───▶ Wiki.js ──▶ athena-indexer ──▶ PostgresWiki.js ist die Quelle der Wahrheit. Der Vektorindex hilft nur beim Auffinden und kann jederzeit gelöscht und neu aufgebaut werden.
Schnellstart | |
Verwendung | |
Produktivbetrieb | |
Referenz |
Schnellstart
Lokal, in etwa fünf Minuten. Für alles im Internet lesen Sie zuerst Auf einem Server bereitstellen.
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 -dDann:
Öffnen Sie Wiki.js und schließen Sie den Setup-Assistenten ab.
In Wiki.js: Administration → API, aktivieren Sie es, erstellen Sie ein Token und setzen Sie es in
.envalsWIKI_API_TOKEN.docker compose up -derneut ausführen, um es zu übernehmen.Öffnen Sie das Dashboard und melden Sie sich mit
DASHBOARD_TOKENan.
Es wird kein Port veröffentlicht. Erreichen Sie die Dienste daher über Ihren Reverse-Proxy oder fügen Sie bei Bedarf vorübergehend ein ports:-Mapping hinzu.
Beim ersten Start wird ein Embedding-Modell von einigen hundert MB heruntergeladen. Der Indexer wiederholt den Vorgang, bis es bereit ist. Es ist daher normal, dass embeddings beim ersten Start ein oder zwei Minuten lang als „unhealthy“ angezeigt wird.
KI verbinden
Alles wird über MCP_PUBLIC_URL bereitgestellt, das eine reine https://-Quelle ohne Pfad sein muss. Nicht /mcp.
Claude.ai → Einstellungen → Connectors → Benutzerdefinierten Connector hinzufügen
URL:
https://athena-mcp.example.com/mcpClient-ID und Secret leer lassen. Athena registriert den Client selbst.
Eine Browserseite fragt nach einem Passwort. Es ist Ihr
MCP_TOKEN.
Cursor, Claude Desktop und andere Header-Clients
{
"mcpServers": {
"athena": {
"url": "https://athena-mcp.example.com/mcp",
"headers": { "Authorization": "Bearer YOUR_MCP_TOKEN" }
}
}
}Werkzeuge
Werkzeug | Funktion |
| Stichwort- und semantische Suche, fusioniert. Jeder Treffer enthält einen Pfad. |
| Vollständiges Markdown einer Seite |
| Überschriftengliederung, ohne den Inhalt |
| Unter einer Überschrift hinzufügen, den Rest unberührt lassen |
| Neue Markdown-Seite |
| Seiteninhalt ersetzen |
| Verschieben oder umbenennen |
| Löschen und aus dem Index entfernen |
| Gespräch unter |
| Kurznotiz in |
| Alle Seiten mit Pfaden und Zeitstempeln |
| Größe, Form und Alter, damit die KI antworten kann, was fehlt |
append_to_page ist das Wichtigste: Das Hinzufügen einer Tatsache kostet einen Absatz, nicht eine Neufassung der ganzen Seite.
Warum die Suche gut funktioniert. Exakte Begriffe treffen den Wiki.js-Volltextindex, vage Fragen den Vektorindex, und die Ergebnisse werden mit Reciprocal Rank Fusion fusioniert, sodass keine Quelle die andere überlagern kann. Abschnitte enthalten die darüberliegenden Überschriften, sodass der zurückgegebene Inhalt seinen Kontext behält. Jede Seite, die ein Assistent berührt, wird mit dem Assistenten und dem Zeitpunkt versehen, die aus dem authentifizierten Client stammen, nicht aus dem, was das Modell über sich selbst behauptet.
Dashboard
Ein eigener Dienst auf Port 8082. Anmelden mit DASHBOARD_TOKEN; es gibt kein Token in einer URL. Für Skripte einen Bearer-Header verwenden:
curl -H "Authorization: Bearer $DASHBOARD_TOKEN" \
https://wiki.example.com/dashboard/api/metrics?days=30Panel | Antworten |
Inhalt | Seiten, Wörter, pro Bereich, größte, veraltete |
KI-Aktivität | Aufrufe pro Tag, welche Werkzeuge, welcher Assistent, Lesen vs. Schreiben |
Suche ohne Treffer | Was Ihr Wiki nicht beantworten konnte |
Index-Zustand | Gespeicherte Abschnitte, indizierte Seiten, Rückstand |
Backup | Wann die letzte Ausführung beendet wurde, wie groß, wohin |
Die dritte Zeile ist die, die sich lohnt. Jeder Eintrag ist eine Seite, die es wert ist, geschrieben zu werden.
Es ist zweifach schreibgeschützt: Es schreibt nie und verbindet sich zu Postgres als athena_readonly, eine Rolle mit SELECT und sonst nichts. Werte werden in Postgres aggregiert und zwischengespeichert, sodass eine Aktualisierung fast nichts kostet.
Auf einem Server bereitstellen
Eine 4-GB-VPS reicht für alles, einschließlich des Embedding-Modells auf der CPU.
1. Host und Firewall
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 enableInstallieren Sie Docker, dann erstellen Sie einen Benutzer, der die Bereitstellung besitzt:
sudo useradd --create-home --shell /bin/bash athena
sudo usermod -aG docker athena
sudo mkdir -p /srv/athena && sudo chown athena:athena /srv/athenaFühren Sie Compose als dieser Benutzer aus, niemals mit sudo, sonst gehören die Bind-Mounts root. Die Mitgliedschaft in der docker-Gruppe entspricht root auf dem Host, also halten Sie sie klein.
2. DNS
Zwei A-Einträge, die auf den Host zeigen:
Name | Bedient |
| Wiki.js und das Dashboard unter |
| den MCP-Endpunkt |
3. Konfiguration
cd /srv/athena
git clone https://github.com/jannismilz/athena.git .
cp .env.example .env
chmod 600 .env # it holds every secretSetzen Sie mindestens:
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. Reverse-Proxy
Kein Container veröffentlicht einen Port. Alles lebt im Docker-Netzwerk athena, das Ihr Proxy beitritt. Leiten Sie diese weiter:
Host | Zu | Anmerkungen |
|
| WebSocket-Upgrade, 100M Body-Limit |
|
| |
|
| darf nicht puffern, MCP-Streams |
Leiten Sie X-Forwarded-For weiter: Die Anmeldungen drosseln pro Adresse, und ohne sie sieht jeder Versuch so aus, als käme er vom Proxy.
Führen Sie nginx als Container aus, der dem Netzwerk athena beitritt, wie unten, oder auf dem Host mit einem ports:-Mapping, das an 127.0.0.1 gebunden ist.
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;
}
}Stellen Sie dann Zertifikate mit certbot aus, oder terminieren Sie TLS dort, wo Sie es bereits tun.
5. Starten, dann das Wiki sperren
docker compose up -d && docker compose psSchließen Sie den Wiki.js-Assistenten sofort ab. Bis Sie das tun, kann jeder, der den Host findet, das Administratorkonto übernehmen. Dann in Wiki.js:
Gruppen → Gäste: Lesezugriff entfernen, es sei denn, Sie möchten das Wiki öffentlich machen.
Authentifizierung: Selbstregistrierung deaktivieren.
API: Aktivieren und das Token für
WIKI_API_TOKENerstellen.
6. Überprüfen
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: 401Backups
Ein pg_dump ist ein vollständiges Backup. Wiki.js speichert Seiten, Verlauf, Benutzer, Berechtigungen, Einstellungen und die Bytes jeder hochgeladenen Datei in Postgres. Uploads leben in der Tabelle assetData; die Dateien unter data/wikijs/uploads sind nur ein Cache. Athenas Aktivitätsprotokoll und Suchvektoren befinden sich in einer zweiten Datenbank auf demselben Server.
Daten | Im Backup enthalten |
Seiten, Verlauf, Benutzer, Einstellungen | ja |
Hochgeladene Bilder und Dateien | ja |
Aktivitätsprotokoll und Suchvektoren | ja |
Index-Buchhaltung, OAuth-Registrierungen | nein, werden neu aufgebaut oder verbunden |
| nein, Kopie in einem Passwortmanager aufbewahren |
Der backup-Container läuft stündlich. Jeder Durchlauf sichert beide Datenbanken, prüft, ob jedes Dump lesbar ist, behält eine lokale Kopie, überträgt an Ihr rclone-Ziel, überprüft, ob der Upload übereinstimmt, und löscht erst dann alte Backups. Ein fehlgeschlagener Durchlauf kann niemals Ihr letztes gutes Backup löschen.
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 scheduleKonfigurieren Sie alles in .env. Jedes rclone-Ziel funktioniert: S3, Backblaze, Wasabi, MinIO, Hetzner. Lassen Sie BACKUP_REMOTE leer, um Backups nur auf dem Host zu behalten.
Fügen Sie ein Crypt-Remote hinzu und setzen Sie BACKUP_REMOTE darauf. Das Ziel erhält dann nur Chiffretext, einschließlich Dateinamen.
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 ...>Bewahren Sie beide Passwörter in Ihrem Passwortmanager auf. Ohne sie sind die Backups unlesbar, auch für Sie.
Wiederherstellen
Üben Sie das, bevor Sie es brauchen. Eine Wiederherstellung, die niemand durchgeführt hat, ist eine Vermutung.
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 dashboardEs fragt Sie, den Datenbanknamen zur Bestätigung einzugeben. restore fetch <stamp> lädt ein Backup herunter, ohne es wiederherzustellen, und meldet, ob jedes Dump lesbar ist.
Der Suchindex repariert sich danach selbst: Der Indexer liest jede Seite erneut und bettet alles neu ein, dessen Inhalt sich geändert hat.
Konfiguration
Alles kommt aus der Umgebung. Jeder Dienst validiert seine eigene Konfiguration beim Start und beendet sich mit einer Liste der Fehler, sodass ein Tippfehler sofort auffällt und nicht um drei Uhr morgens.
Die fünf Geheimnisse, alle von Ihnen generiert. Keine Anmeldeinformationen von Claude, OpenAI oder sonst jemandem werden jemals in .env gespeichert.
Geheimnis | Gehalten von | Schützt |
| postgres, mcp, indexer | vollständiger Datenbankzugriff |
| mcp, indexer | die Wiki.js-API |
| mcp | den MCP-Endpunkt |
| dashboard | die Dashboard-Anmeldung |
| dashboard, mcp, indexer | eine SELECT-only Datenbankrolle |
Was läuft
Dienst | Port | Was es ist |
| intern | Wiki.js-Daten, Aktivitätsprotokoll und Vektoren über pgvector |
| 3000 | Das Wiki, das Sie lesen und bearbeiten |
| intern | Das Embedding-Modell auf der CPU |
| 8080 | Das, womit Ihre KI verbindet |
| 8081 | Hält den Vektorindex auf dem neuesten Stand mit dem Wiki |
| 8082 | Metriken |
| keiner | Stündlicher Dump, Prüfung, Übertragung |
Es gibt keine separate Vektordatenbank. Vektoren leben in Postgres, sodass ein Backup alles abdeckt.
Auf ARM-Hosts wird das Embedding-Image nur für
linux/amd64veröffentlicht und läuft nicht nativ. Setzen Sie stattdessenEMBEDDINGS_PROVIDER=openaiauf einen OpenAI-kompatiblen Endpunkt wie Ollama.
Variable | Standard | Hinweise |
|
| Wurzel jedes Bind-Mounts |
|
| Wird auf der Anmeldeseite und im Dashboard angezeigt |
|
|
|
|
| Herkunftsstempel und datumsbasierte Pfade |
|
| Die Wiki.js-Datenbank |
|
| Aktivitätslog und Vektoren, automatisch erstellt |
|
| Inhaltssprache |
|
| Wird für Dashboard-Links verwendet |
| erforderlich | Reiner HTTPS-Origin, ohne Pfad |
|
| Wie lange Dashboard-Zahlen wiederverwendet werden |
|
| Ändern indiziert alles neu |
|
|
|
|
| Vollständiges Abgleichsintervall |
|
| Maximale Chunk-Größe |
| siehe | Zeitplan, Aufbewahrung, rclone-Ziel |
Wenn EMBEDDINGS_MODEL geändert wird, ändert sich die Vektorbreite, und Vektoren von zwei Modellen können nicht verglichen werden. Daher baut der Indexer die Tabelle neu auf und bettet jede Seite erneut ein. Der Inhalt von Wiki.js bleibt unberührt.
Sicherheit
Jeder Container erhält nur die Zugangsdaten, die er verwendet. Das Dashboard bekommt weder POSTGRES_PASSWORD noch WIKI_API_TOKEN, sodass ein Kompromittieren nur Lesezugriff und nichts weiter ergibt. Jederzeit prüfbar:
docker inspect athena-dashboard -f '{{range .Config.Env}}{{println .}}{{end}}' | grep -iE 'PASSWORD|TOKEN'Nicht authentifizierte MCP-Anfragen erhalten 401 und keine Erklärung.
Beide Anmeldepfade drosseln nach 5 Fehlversuchen pro Adresse; ein Anmeldelink verfällt nach 3 Versuchen.
Dashboard-Sitzungen sind signierte Cookies, die ein Ablaufdatum und eine Nonce enthalten, niemals den Token.
HttpOnly,SameSite=Strict, und siteübergreifende POSTs werden abgelehnt.Geheimnisvergleiche erfolgen in konstanter Zeit.
Proxy-Header werden nur von Loopback vertraut, sodass ein entfernter Client seine Adresse nicht fälschen kann, um einer Drosselung zu entgehen.
Container laufen als Nicht-Root-Benutzer.
Bewusst nicht vorhanden: Berechtigungen pro Tool. Jeder authentifizierte Client kann jedes Tool aufrufen, einschließlich delete_page. Wiki.js behält die Seitenhistorie, sodass ein Löschen wiederherstellbar ist, aber behandeln Sie MCP_TOKEN als vollständigen Schreibzugriff auf Ihr Wiki. Athena geht außerdem von einem einzigen Besitzer aus; Wiki.js hat eigene Benutzer zum Lesen des Wikis.
MCP_TOKEN funktioniert auf zwei Arten, weil KI-Clients sich auf zwei Arten authentifizieren.
Header-Clients wie Cursor und Claude Desktop senden Authorization: Bearer <MCP_TOKEN>. Das ist der gesamte Mechanismus.
Claude.ai im Browser kann das nicht. Seine benutzerdefinierten Konnektoren unterstützen nur OAuth, und die MCP-Spezifikation erfordert eine dynamische Client-Registrierung. Daher muss ein Server, der Browser-Claude akzeptiert, selbst ein Autorisierungsserver sein. Athena implementiert einen:
Claude registriert sich und erhält eine generierte Client-ID. Ihr Geheimnis ist nicht beteiligt.
Claude sendet Sie zu einer Anmeldeseite auf Ihrem eigenen Server.
Sie geben
MCP_TOKENals Passwort ein. Das ist der Schritt der menschlichen Genehmigung.Athena stellt Claude-Token aus, die Athena selbst geprägt hat.
Diese Token werden in data/mcp/oauth-state.json geschrieben, niemals in .env. Widerrufen Sie sie mit:
rm data/mcp/oauth-state.json && docker compose restart mcpWenn Sie Browser-Claude nie verwenden, ignorieren Sie das alles. Der Bearer-Pfad berührt es nicht.
Betrieb
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"})'Upgrade. Erstellen Sie immer zuerst ein Backup: Wiki.js führt beim Start eigene Migrationen durch, die nicht durch Stoppen des Containers umkehrbar sind.
docker compose run --rm backup now
git pull && docker compose build && docker compose up -dSymptom | Ursache |
Ein Dienst beendet sich beim Start mit Konfiguration | Eine erforderliche Variable fehlt oder ist noch |
Claude kann keine Verbindung herstellen, keine Anmeldeseite |
|
Anmeldung lehnt das richtige Passwort ab | Nach 5 Fehlversuchen gedrosselt, eine Minute warten |
Keine semantischen Suchergebnisse |
|
Dashboard zeigt veraltete Seiten | Indexer holt auf, Logs prüfen |
Tool-Aufrufe schlagen mit 401 fehl | Zustandsdatei gelöscht oder Token geändert, Client neu verbinden |
Postgres beendet sich, „Datenbankdateien sind inkompatibel“ | Die Hauptversion des Images wurde unter vorhandenen Daten geändert |
Postgres kann kein Datenverzeichnis lesen, das von einer anderen Hauptversion geschrieben wurde. Dump, leeren, wiederherstellen:
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 -dDer Vektorindex wird mit allem anderen wiederhergestellt, sodass nichts neu eingebettet wird.
Entwicklung
bun install
bun test # 145 tests
bun run check # typecheck, lint, testPaket | Beschreibung |
| Wiki.js-Client, Chunking, Suchzusammenführung, Vektoren, Auth, Konfiguration |
| MCP-Server, OAuth-Autorisierungsserver, die Tools |
| Sync-Schleife, Embeddings, Vektor-Schreibvorgänge, interne Such-API |
| Metrik-Oberfläche |
| Backup- und Wiederherstellungs-Container |
| Die einseitige Website |
| Optionales Wiki.js-CSS und -JS |
Bun führt TypeScript direkt aus, daher gibt es keinen Build-Schritt und die Container führen den Quellcode aus. bun run --cwd packages/dashboard preview schreibt eine preview.html mit Beispieldaten.
Wie alles zusammenhängt:
Der Indexer arbeitet inkrementell. Er erstellt einen Fingerabdruck jeder Seite und überspringt alles Unveränderte, sodass ein Durchlauf über ein unberührtes Wiki nichts kostet.
Jeder Dienst mit Administrator-Zugangsdaten bereitet die Datenbank beim Start unter einer beratenden Sperre (advisory lock) vor, sodass die Startreihenfolge keine Rolle spielt.
Das Dashboard ist serverseitig gerendertes HTML mit Inline-SVG-Diagrammen. Kein clientseitiges JavaScript, keine Diagrammbibliothek, kein Build-Schritt.
Veröffentlichen der Website. website/index.html wird bei jedem Push, der sie betrifft, auf GitHub Pages bereitgestellt. Aktivieren Sie Pages einmal manuell: Einstellungen → Pages → Build und Deployment → Quelle: GitHub Actions. Dies kann nicht automatisiert werden, da das Erstellen einer Pages-Site einen Token mit Administratorrechten erfordert und GITHUB_TOKEN diese nicht besitzt.
Lizenz
Apache-2.0. Siehe 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