COMPASS-Doku

Claude Code, Cursor und Codex anbinden

Der MCP-Server (mcp/server.py) unterstützt zwei Transporte, gewählt über die Umgebungsvariable COMPASS_MCP_TRANSPORT auf dem Server-Prozess (Standard stdio). Welcher es ist, ändert, woher der Schlüssel kommt — das falsch zu machen bringt entweder ein verwirrendes 401 oder, im alten abgelösten Verhalten, still die Daten eines anderen Mandanten.

stdio — Claude Code und Cursor, lokal

Der Client startet mcp/server.py selbst als Unterprozess. Der Schlüssel lebt in der Prozess-Umgebung, die man ihm mitgibt — es gibt keinen separaten Aufrufer, dessen Kopfzeile man lesen könnte, deshalb sind COMPASS_KEY_RO/COMPASS_KEY_RW in diesem Modus die einzige Quelle.

Claude Code (.mcp.json) und Cursor (.cursor/mcp.json) nutzen dieselbe Form:

{
  "mcpServers": {
    "compass": {
      "command": "/pfad/zu/mcp/.venv/bin/python",
      "args": ["/pfad/zu/mcp/server.py"],
      "env": {
        "COMPASS_CORE_URL": "http://localhost:18080",
        "COMPASS_KEY_RO": "<Lese-Schlüssel>",
        "COMPASS_KEY_RW": "<Schreib-Schlüssel>"
      }
    }
  }
}
  • COMPASS_CORE_URL — Basis-URL des Kerns, ohne /api/v1 (Standard http://localhost:18080).
  • COMPASS_KEY_RO — für lesende Werkzeuge; fehlt er, fallen lesende Werkzeuge auf COMPASS_KEY_RW zurück.
  • COMPASS_KEY_RW — für schreibende Werkzeuge; fehlt er, wird ein Schreib-Aufruf clientseitig verweigert statt ohne Schlüssel abgesetzt.

Codex

Codex CLI liest MCP-Server aus ~/.codex/config.toml, als Tabelle [mcp_servers.<name>] mit derselben command/args/env-Form:

[mcp_servers.compass]
command = "/pfad/zu/mcp/.venv/bin/python"
args = ["/pfad/zu/mcp/server.py"]

[mcp_servers.compass.env]
COMPASS_CORE_URL = "http://localhost:18080"
COMPASS_KEY_RO = "<Lese-Schlüssel>"
COMPASS_KEY_RW = "<Schreib-Schlüssel>"

streamable-http — ein laufender Container

Auf https://<host>/mcp zeigen (lokal http://localhost:18082/mcp). In diesem Modus läuft der ausgerollte MCP, und er nimmt zwei Zugangsmittel — genau eines je Anfrage, nie beide zusammen.

Der erste Weg: OAuth, ohne Schlüssel

Ein Client, der OAuth spricht, braucht keinen Schlüssel in seiner Konfiguration. Bei Claude Code sind es zwei Schritte:

claude mcp add --transport http compass https://<host>/mcp

Danach im Chat /mcp → „Authenticate": der Browser öffnet die Zustimmungsseite, ihr meldet euch an und gebt den Zugriff frei. Bis dahin sagt claude mcp list „Needs authentication" — das ist kein Fehler, sondern der Zustand vor der Zustimmung.

Die Sitzung hängt dann an dem Menschen, der zugestimmt hat, mit dessen Rolle und Mandant. Ist auf dem Server kein Signierschlüssel für die Tür gesetzt (COMPASS_MCP_OAUTH_SIGNING_KEY), antworten die OAuth-Pfade mit 503 und nennen die fehlende Variable — sie fallen nicht still auf offenen Zugriff zurück. Der Schlüsselweg ist davon unberührt.

Der zweite Weg: Schlüssel als Kopfzeile

Mit Schlüssel statt OAuth, wenn der Agent als eine bestimmte Persona arbeiten soll (ihr Brief, ihre Grenzen) oder ohne Browser läuft — etwa auf einem Server. Ein Schlüssel kann an eine Persona gebunden sein, eine OAuth-Sitzung nie: sie gehört dem angemeldeten Menschen.

{
  "mcpServers": {
    "compass": {
      "url": "http://localhost:18082/mcp",
      "transport": "http",
      "headers": { "X-Compass-Key": "<Schlüssel dieses Mandanten>" }
    }
  }
}

Auf diesem Weg ist der headers-Block Pflicht, nicht optional — wer weder Schlüssel noch OAuth-Zugangsband mitbringt, kommt nicht durch, und wer beides zugleich schickt, wird mit „Zugangsmittel sind mehrdeutig" abgewiesen. Liegt eine echte eingehende HTTP-Anfrage vor, liest der Server den Schlüssel ausschließlich aus deren eigener X-Compass-Key-Kopfzeile — kein Rückfall auf einen im Prozess gesetzten Schlüssel, selbst wenn einer zufällig gesetzt ist. Fehlt die Kopfzeile, wird der Aufruf verweigert, bevor der Kern überhaupt kontaktiert wird:

{"status": 401, "detail": "X-Compass-Key fehlt in der Anfrage — kein Ruecksprung auf den Prozess-Schluessel."}

Das ist wichtig, weil derselbe Schlüssel beides bestimmt: welchen Mandanten man sieht und was man darf (ro/rw/bruecke — siehe Konzepte) — dieselbe Kopfzeile gilt für jedes Werkzeug, lesend oder schreibend; der Kern entscheidet serverseitig, ob sie reicht.

Ohne Schlüssel verbinden — was ihr dabei seht

Clients, die OAuth sprechen, brauchen keinen Schlüssel in der Konfiguration. Sie schicken euch stattdessen einmalig in den Browser, und dort entscheidet ihr selbst.

Was auf der Seite steht:

  • Wer fragt. Der Name, unter dem sich der Client angemeldet hat. Erkennt ihr ihn nicht, lehnt ab.
  • Als wer ihr angemeldet seid. Eure Adresse, so wie COMPASS sie kennt.
  • Mit welchem Projekt. Gehört ihr zu mehreren, ist die Wahl Pflicht und es ist nichts vorausgewählt — sonst klickt man die falsche Antwort durch. Gehört ihr zu genau einem, wird gar nicht gefragt.
  • Was der Client darf, in ganzen Sätzen: lesen, eintragen, und was ausdrücklich nicht geht — Schlüssel sehen, Mitglieder ändern, etwas löschen. Ist euer Zugang nur lesend, steht das Eintragen dort unter „Nicht", mit dem Grund.

Dann zwei Knöpfe: Erlauben oder Ablehnen. Lehnt ihr ab, entsteht nichts, und der Client bleibt unverbunden.

Geht etwas schief, sagt die Seite welches von diesen vier Dingen es war, statt nur „Fehler":

Was dasteht Was es heißt
Anmeldung abgelaufen Das Fenster stand zu lange offen. Nichts ist passiert — in eurem Client noch einmal auf „Verbinden".
Falsches Projekt Das Konto, mit dem ihr angemeldet seid, hat keinen Zugriff auf dieses Projekt. Mit einem anderen Konto anmelden, oder oben ein anderes Projekt wählen.
Unbekannter Assistent Das anfragende Programm konnte sich nicht ausweisen. COMPASS verbindet es nicht. Habt ihr es selbst eingerichtet, nehmt den Weg mit Schlüssel.
COMPASS antwortet gerade nicht Es wurde nichts gespeichert und nichts verbunden. Noch einmal versuchen.

Die Seite spricht Deutsch oder Englisch, je nachdem, was euer Browser verlangt; im Zweifel Deutsch.

Nach dem Verbinden wählt ihr im Chat die Persona, mit persona_waehlen. Erst damit steht fest, als wer der Assistent schreibt und was er sehen darf. Ohne Wahl bleibt alles so, wie es ohne sie war.

Welcher Transport für welchen Client

Client Typische Einrichtung Transport Schlüsselquelle
Claude Code, lokal startet server.py selbst stdio Prozess-Umgebung
Cursor, lokal startet server.py selbst stdio Prozess-Umgebung
Codex, lokal startet server.py selbst stdio Prozess-Umgebung
Claude Code, gegen den ausgerollten Server claude mcp add --transport http streamable-http OAuth, kein Schlüssel
Beliebiger Client, gegen einen geteilten/ausgerollten Server verbindet über HTTP streamable-http Kopfzeile je Anfrage oder OAuth

Verbindung prüfen

Nach dem Verbinden ist ein lesendes Werkzeug ohne Abhängigkeit von vorhandenen Daten die günstigste Probe:

persona_list()

oder, aus der Shell, der entsprechende REST-Aufruf:

curl -sS "$COMPASS_URL/personas" -H "X-Compass-Key: $COMPASS_KEY"

Ein 401 hier bedeutet: Schlüssel oder Kopfzeile passen nicht zum gewählten Transport — zuerst die Tabelle oben prüfen, bevor man annimmt, der Server selbst sei nicht erreichbar.