Skip to main content
Glama

zulipmcp

License: MIT Python 3.10+

Führe KI-Agenten in Zulip als @erwähnbare Bots aus – oder binde sie in einen beliebigen MCP-Client ein. Funktioniert auch als Python-Bibliothek.

Schnellstart

  1. Installiere das Paket:

    uv add zulipmcp --git https://github.com/windborne/zulipmcp.git
  2. Füge eine .zuliprc-Datei mit deinen Zulip-Bot-Anmeldedaten zum Stammverzeichnis deines Projekts hinzu. Siehe Einen Bot oder eine Integration hinzufügen für Anweisungen zur Erstellung eines Bots. Der Bot-Typ muss „generic“ sein.

  3. Füge den MCP-Server zu deiner .mcp.json hinzu:

    {
      "mcpServers": {
        "zulip": {
          "command": "uv",
          "args": ["run", "python", "-m", "zulipmcp.mcp"]
        }
      }
    }
  4. Starte deinen MCP-Client neu. Die Zulip-Tools sollten nun verfügbar sein.

Anforderungen

  • Python >=3.10, verwaltet mit uv

  • Eine .zuliprc-Datei für die Zulip-API-Authentifizierung (siehe Schnellstart)

Einstiegspunkte

Einstiegspunkt

Beschreibung

uv run python -m zulipmcp.mcp

MCP-Server für Claude Code / MCP-Clients

uv run python -m zulipmcp.mcp --transport sse

MCP-Server über SSE (für Remote-/Web-Clients)

uv run python -m zulipmcp.listener

Listener: überwacht @Erwähnungen, startet Claude Code-Sitzungen

Verwendung als Bibliothek

zulipmcp kann auch direkt als Python-Bibliothek importiert werden:

import zulipmcp

# Fetch and format recent messages
messages = zulipmcp.get_messages(hours_back=24, channels=["engineering"])
print(zulipmcp.format_messages(messages))

# Send a message
zulipmcp.send_message("engineering", "general", "Hello from Python!")

# Configure MCP hooks before starting the server
zulipmcp.configure(
    message_prefix=lambda: "[bot] ",
    on_session_end=lambda session: print(f"Session ended in #{session.stream}"),
)

Listener

Das optionale Modul zulipmcp.listener überwacht Zulip auf @Erwähnungen und startet eine Headless-Claude-Code-Sitzung pro (Stream, Thema). Es ist das Bindeglied zwischen Zulip-Ereignissen und Claude Code – der MCP-Server kümmert sich um alle Zulip-Tools, der Listener verwaltet lediglich den Lebenszyklus.

# Minimal -- uses ./.zuliprc, ./.mcp.json (if present), and the bundled default prompt
uv run python -m zulipmcp.listener

# Full -- override MCP config and system prompt
uv run python -m zulipmcp.listener \
    --mcp-config .mcp.json \
    --system-prompt agent.md \
    --log-dir ./logs

# Pass flags through to Claude Code (everything after --)
uv run python -m zulipmcp.listener -- --strict-mcp-config --model opus

Flags:

Flag

Standard

Beschreibung

--zuliprc

./.zuliprc

Pfad zur .zuliprc (relativ zum aktuellen Arbeitsverzeichnis aufgelöst)

--mcp-config

./.mcp.json

Pfad zur .mcp.json für Claude Code-Sitzungen (wird nur verwendet, wenn die Datei existiert)

--system-prompt

zulipmcp/default_system_prompt.md

Datei für den angehängten System-Prompt (Standardpfad wird relativ zu listener.py aufgelöst, nicht zum aktuellen Arbeitsverzeichnis)

--working-dir

.

Arbeitsverzeichnis für gestartete Sitzungen

--claude-command

claude

Name oder Pfad der Claude CLI-Binärdatei

--log-dir

./logs

Verzeichnis für Sitzungsprotokolldateien

-- ...

(keine)

Alles nach -- wird unverändert an claude weitergeleitet

Jede Sitzung erhält automatisch TRIGGER_MESSAGE_ID und SESSION_USER_EMAIL, sodass set_context() an der @Erwähnung verankert wird und Hooks den Anfragenden identifizieren können.

Der Listener ist bewusst minimal gehalten (~230 Zeilen). Er verzichtet auf Nebenläufigkeitsbegrenzungen, Arbeitsbereichsisolierung, Watchdogs für veraltete Sitzungen und Dashboards – füge diese hinzu, wenn du sie benötigst.

Wichtige Designdetails

Auf Nachrichten warten

Das listen-Tool verwendet die Echtzeit-Ereignis-API von Zulip (Long-Polling) anstelle von wiederholten GET /messages-Aufrufen. Beim Start holt es alle Nachrichten seit der last_seen_message_id nach, abonniert bei Bedarf den Stream für den Bot, registriert eine eingeschränkte Ereigniswarteschlange für den Stream/das Thema und führt dann Long-Polling über GET /events durch. Der Server blockiert, bis eine Nachricht eintrifft oder ca. 90 Sekunden vergangen sind (Heartbeat), was dies ca. 30-mal effizienter macht als ein Polling alle 2 Sekunden. Wenn die Warteschlange abläuft (BAD_EVENT_QUEUE_ID), erfolgt eine automatische Neuregistrierung. Die Warteschlange wird beim Beenden in einem finally-Block gelöscht.

Ein :robot_ear:-Emoji wird während des Wartens als visuelle Anzeige an die letzte Nachricht angehängt und entfernt, wenn das Warten aufhört. MCP-Keepalive-Pings werden nach jedem Long-Polling-Zyklus über ctx.info() gesendet.

Keine verpassten Nachrichten bei Antworten

Wenn reply aufgerufen wird, prüft es vor dem Senden auf neue Nachrichten. Falls jemand gepostet hat, während das LLM nachdachte, werden diese Nachrichten abgerufen und zusammen mit der Bestätigung „Nachricht gesendet“ zurückgegeben. Auf diese Weise sieht das LLM immer, was es verpasst hat, und kann entsprechend reagieren. Die last_seen_message_id wird auf den neuesten Stand gebracht – entweder die verpassten Nachrichten oder die gesendete Nachricht –, damit nichts verloren geht.

Beenden von Sitzungen

Benutzer können eine Bot-Sitzung beenden, indem sie mit einem konfigurierbaren Emoji (Standard: :stop_sign:) auf eine beliebige Bot-Nachricht reagieren. Die Prüfung auf Beendigung erfolgt sowohl während listen() (über Reaktionsereignisse) als auch vor reply() (über REST-API-Polling), was die Race Condition abdeckt, bei der ein Benutzer reagiert, während der Bot beschäftigt ist. Anpassbar mit configure(dismiss_emoji={"stop_sign", "wave"}).

Filterung der Bot-Sichtbarkeit

Themen, die /nobots oder /nb enthalten, sind für den Bot vollständig ausgeblendet. Nachrichten, die mit /nobots oder /nb beginnen, werden ebenfalls herausgefiltert. Dies ermöglicht es Menschen, private Unterhaltungen zu führen, die der Bot nicht sieht.

Umgebungsvariablen

Variable

Beschreibung

ZULIP_RC_PATH

Absoluter Pfad zur .zuliprc. Überschreibt den Standard (./.zuliprc im aktuellen Arbeitsverzeichnis).

TRIGGER_MESSAGE_ID

Nachrichten-ID, die die Sitzung ausgelöst hat (z. B. die @Erwähnung). Legt den Anker für das Warten fest, damit der Agent keine Nachrichten nach dem Auslöser verpasst.

SESSION_USER_EMAIL

E-Mail des Menschen, der die Sitzung ausgelöst hat. Wird für Hooks in SessionState gespeichert.

SESSION_STREAM

Stream-Name für die automatische Initialisierung einer Sitzung beim Serverstart (nur für direkte run_server()-Aufrufer – der Listener verwendet diese nicht). Sowohl SESSION_STREAM als auch SESSION_TOPIC müssen gesetzt sein; der Agent kann dann set_context() überspringen.

SESSION_TOPIC

Thema für die automatische Initialisierung. Erfordert SESSION_STREAM.

BOT_ALLOWED_PRIVATE_STREAMS

Zulassungsliste für das Lesen/Senden in privaten Streams. Nicht gesetzt = kein Zugriff auf private Streams. Akzeptiert __ALL__, eine JSON-Liste oder durch Kommas getrennte Namen.

BOT_ALLOWED_WRITE_STREAMS

Zulassungsliste für das Senden in Streams. Nicht gesetzt = Schreiben überall erlaubt (abwärtskompatibel). Gleiche Formate wie oben.

ZULIPMCP_CACHE_DIR

Überschreibt das Festplatten-Cache-Verzeichnis (Standard ist das temporäre Systemverzeichnis).

ZULIPMCP_LOG_DIR

Überschreibt das Protokollverzeichnis (Standard ist /tmp/zulipmcp_logs).

Lizenz

MIT

Install Server
A
security – no known vulnerabilities
A
license - permissive license
A
quality - A tier

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/windborne/zulipmcp'

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