Skip to main content
Glama

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

Wiki.js ist die Quelle der Wahrheit. Der Vektorindex hilft nur beim Auffinden und kann jederzeit gelöscht und neu aufgebaut werden.


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 -d

Dann:

  1. Öffnen Sie Wiki.js und schließen Sie den Setup-Assistenten ab.

  2. In Wiki.js: Administration → API, aktivieren Sie es, erstellen Sie ein Token und setzen Sie es in .env als WIKI_API_TOKEN.

  3. docker compose up -d erneut ausführen, um es zu übernehmen.

  4. Öffnen Sie das Dashboard und melden Sie sich mit DASHBOARD_TOKEN an.

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/mcp

  • Client-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

search_knowledge

Stichwort- und semantische Suche, fusioniert. Jeder Treffer enthält einen Pfad.

get_page

Vollständiges Markdown einer Seite

get_page_structure

Überschriftengliederung, ohne den Inhalt

append_to_page

Unter einer Überschrift hinzufügen, den Rest unberührt lassen

create_page

Neue Markdown-Seite

update_page

Seiteninhalt ersetzen

move_page

Verschieben oder umbenennen

delete_page

Löschen und aus dem Index entfernen

save_conversation

Gespräch unter conversations/YYYY/MM/ ablegen

capture_note

Kurznotiz in inbox/ zur späteren Ablage

list_pages

Alle Seiten mit Pfaden und Zeitstempeln

get_wiki_stats

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=30

Panel

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 enable

Installieren 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/athena

Fü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.example.com

Wiki.js und das Dashboard unter /dashboard/

athena-mcp.example.com

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 secret

Setzen 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.com

4. 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

wiki.example.com

wikijs:3000

WebSocket-Upgrade, 100M Body-Limit

wiki.example.com/dashboard/

dashboard:8082

athena-mcp.example.com

mcp:8080

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 ps

Schließ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_TOKEN erstellen.

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: 401

Backups

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

.env

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 schedule

Konfigurieren 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 dashboard

Es 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_PASSWORD

postgres, mcp, indexer

vollständiger Datenbankzugriff

WIKI_API_TOKEN

mcp, indexer

die Wiki.js-API

MCP_TOKEN

mcp

den MCP-Endpunkt

DASHBOARD_TOKEN

dashboard

die Dashboard-Anmeldung

DASHBOARD_DB_PASSWORD

dashboard, mcp, indexer

eine SELECT-only Datenbankrolle

Was läuft

Dienst

Port

Was es ist

postgres

intern

Wiki.js-Daten, Aktivitätsprotokoll und Vektoren über pgvector

wikijs

3000

Das Wiki, das Sie lesen und bearbeiten

embeddings

intern

Das Embedding-Modell auf der CPU

mcp

8080

Das, womit Ihre KI verbindet

indexer

8081

Hält den Vektorindex auf dem neuesten Stand mit dem Wiki

dashboard

8082

Metriken

backup

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/amd64 veröffentlicht und läuft nicht nativ. Setzen Sie stattdessen EMBEDDINGS_PROVIDER=openai auf einen OpenAI-kompatiblen Endpunkt wie Ollama.

Variable

Standard

Hinweise

ATHENA_DATA_DIR

./data

Wurzel jedes Bind-Mounts

ATHENA_INSTANCE_NAME

Athena

Wird auf der Anmeldeseite und im Dashboard angezeigt

ATHENA_LOG_LEVEL

info

debug, info, warn, error

TZ

UTC

Herkunftsstempel und datumsbasierte Pfade

POSTGRES_DB

wiki

Die Wiki.js-Datenbank

ATHENA_DB

athena

Aktivitätslog und Vektoren, automatisch erstellt

WIKI_LOCALE

en

Inhaltssprache

WIKI_PUBLIC_URL

http://localhost:3000

Wird für Dashboard-Links verwendet

MCP_PUBLIC_URL

erforderlich

Reiner HTTPS-Origin, ohne Pfad

METRICS_CACHE_SECONDS

60

Wie lange Dashboard-Zahlen wiederverwendet werden

EMBEDDINGS_MODEL

intfloat/multilingual-e5-small

Ändern indiziert alles neu

EMBEDDINGS_PROVIDER

tei

tei oder openai für einen kompatiblen Endpunkt

INDEX_INTERVAL_SECONDS

300

Vollständiges Abgleichsintervall

CHUNK_MAX_CHARS

1200

Maximale Chunk-Größe

BACKUP_*

siehe .env.example

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:

  1. Claude registriert sich und erhält eine generierte Client-ID. Ihr Geheimnis ist nicht beteiligt.

  2. Claude sendet Sie zu einer Anmeldeseite auf Ihrem eigenen Server.

  3. Sie geben MCP_TOKEN als Passwort ein. Das ist der Schritt der menschlichen Genehmigung.

  4. 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 mcp

Wenn 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 -d

Symptom

Ursache

Ein Dienst beendet sich beim Start mit Konfiguration

Eine erforderliche Variable fehlt oder ist noch CHANGE_ME

Claude kann keine Verbindung herstellen, keine Anmeldeseite

MCP_PUBLIC_URL hat einen Pfad oder ist nicht https

Anmeldung lehnt das richtige Passwort ab

Nach 5 Fehlversuchen gedrosselt, eine Minute warten

Keine semantischen Suchergebnisse

embeddings lädt noch herunter, Logs prüfen

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 -d

Der Vektorindex wird mit allem anderen wiederhergestellt, sodass nichts neu eingebettet wird.


Entwicklung

bun install
bun test          # 145 tests
bun run check     # typecheck, lint, test

Paket

Beschreibung

packages/core

Wiki.js-Client, Chunking, Suchzusammenführung, Vektoren, Auth, Konfiguration

packages/mcp

MCP-Server, OAuth-Autorisierungsserver, die Tools

packages/indexer

Sync-Schleife, Embeddings, Vektor-Schreibvorgänge, interne Such-API

packages/dashboard

Metrik-Oberfläche

docker/backup

Backup- und Wiederherstellungs-Container

website/

Die einseitige Website

themes/wikijs/

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.

-
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