Abonnieren Sie Veranstaltungen über MCP
Ein KI-Agent, der über MCP mit Kanera verbunden ist, kann anstelle einer Abfrage eine Benachrichtigung über Arbeitsänderungen anfordern. Kanera implementiert die Webhook-Zustellung des Entwurfs MCP-Veranstaltungen Erweiterung: Der Host des Agenten registriert einen HTTPS-Rückruf, Kanera überprüft ihn und von da an wird jede übereinstimmende Änderung als signiertes JSON-Vorkommen an ihn gesendet.
Dies ist der Mechanismus hinter „Beobachten Sie dieses Forum und sagen Sie mir, wenn ein Kommentar landet“ in einem Client wie ChatGPT. Der Host ist Eigentümer des Rückrufs. Sie betreiben keinen Server und fügen nirgendwo in Kanera eine URL ein.
Was ein Agent abonnieren kann
| Veranstaltung | Wird ausgelöst, wenn | Zusätzliche Felder in data |
|---|---|---|
card.created | Im überwachten Bereich wird eine Karte erstellt. | title, listId, url |
card.updated | Eine Karte ändert sich: Titel, Beschreibung, Abschluss, Archivstatus und andere Kartenfelder. | title, listId, url |
card.moved | Eine Karte bewegt sich innerhalb oder zwischen Listen oder Boards. | listId (das Ziel), fromListId (die Quelle), prevPosition, url |
card.blocked | Eine aktive Karte erhält ihren ersten offenen Blocker, einschließlich Wiedereröffnung oder Wiederherstellung. | title, listId, url; Keine Blockerdetails |
card.unblocked | Eine aktive Karte verliert ihren letzten offenen Blocker durch Vervollständigung, Archivierung, Aufhebung der Verknüpfung oder Entfernung des Blocker-Boards oder der Blocker-Liste. | title, listId, url; Keine Blockerdetails |
schedule.conflict_detected | Eine offene Karte erhält ihren ersten Planungskonflikt: Es ist geplant, dass ein offener Blocker bei oder nach seinem Start endet. | blockerCardId, days (Arbeitstage, an denen der Angehörige umziehen müsste) |
schedule.conflict_resolved | Eine offene Karte verliert ihren letzten Planungskonflikt. | Keine zusätzlichen Zeitplanfelder |
schedule.critical_path_slipped | Das geplante Ende einer Karte mit kritischem Pfad verschiebt sich später und verzögert das geplante Ende des Spielplans. | previousProjectedFinish, projectedFinish, days, slipDays |
comment.created | Ein Kommentar wird auf einer Karte gepostet. | commentId, text (bis zu 8.000 Zeichen), url |
priorities.changed | Ihr eigenes „Als Nächstes“ Die Warteschlange hat sich möglicherweise geändert. | Keine. Siehe Ihre nächste Warteschlange. |
my_day.ready | Es ist ein Wochentagmorgen in Ihrer Zeitzone. | localDate, timeZone. Siehe Ihr morgendliches Briefing. |
reminder.due | Einer von Ihnen Kartenerinnerungen kommt fällig. | reminderId, cardId, remindAt, url. Siehe Ihre Kartenerinnerungen. |
Jede Karte und jedes Kommentarvorkommen trägt workspaceId, boardId, cardId, und ein actor (siehe Erzählen Sie Ihre eigenen Texte auseinander). Nutzlasten sind begrenzte Zusammenfassungen: Die Beschreibung, Anhänge und der vollständige Kommentarthread einer Karte sind niemals enthalten. Der Agent liest den aktuellen Datensatz mit cards.get oder comments.list wenn es mehr braucht.
Für Karten-, Kommentar- und Zeitplanereignisse Abonnement Argumente Grenzen Sie ein, was geliefert wird:
| Argument | Erforderlich | Wirkung |
|---|---|---|
workspaceId | Ja | Nur Ereignisse in diesem Arbeitsbereich. |
boardId | Nein | Nur Ereignisse auf diesem Forum. Für Bordgäste erforderlich. |
listId | Nein | Nur Ereignisse für Karten in dieser Arbeitsbereichsliste. Für card.moved, eine Karte, die in die Liste aufgenommen oder aus ihr entfernt wird, stimmt überein, Neuordnungen darin nicht. Weglassen boardId um die freigegebene Liste auf jedem zugänglichen Board anzusehen. |
cardId | Nein | Nur Ereignisse für diese Karte. Erfordert boardId. |
Der Zugriff folgt der verbundenen Identität bei jeder Lieferung, nicht nur zum Zeitpunkt des Abonnements. Ein Workspace-Mitglied kann den gesamten Workspace beobachten; ein organisationsübergreifender Gast muss einen Board benennen, zu dem er eingeladen wurde; Ein Gast, der auf zugewiesene Gegenstände beschränkt ist, muss eine Karte benennen, der er derzeit zugewiesen ist. Wenn die Identität später den Zugriff auf den Bereich verliert, wird die Zustellung gestoppt und das Abonnement läuft ab. Durch den Verlust des Zugriffs auf eine Karte innerhalb eines Board-weiten Abonnements wird nur dieser Vorfall übersprungen.
Abhängigkeitsübergänge
card.blocked und card.unblocked folgen Kartenabhängigkeiten, einschließlich Änderungen von Personen, Integrationen, Automatisierungen und gespiegelten Karten. Sie erfordern keine Automatisierungsregel. Durch das Hinzufügen eines weiteren Blockers oder das Entfernen nur eines von mehreren Blockern wird der Übergang nicht wiederholt. Jede Richtung ist auf einmal pro Karte und Transaktion beschränkt.
Das Ereignis beschreibt die abhängige Karte und lässt Blockerdetails weg, um private Boards zu schützen. Lesen cards.get für die aktuellen Beziehungen, die für Ihre Verbindung sichtbar sind. Überprüfen Sie den aktuellen Status, bevor Sie handeln, da die Karte möglicherweise bereits durch eine Automatisierung verschoben oder fertiggestellt wurde.
Planen Sie Übergänge
Die drei schedule.* Ereignisse verwenden dieselbe Arbeitstags-Engine wie die Zeitleistenansicht und work.schedule. Sie erfordern die Aktivierung der Zeitleiste und der Abhängigkeiten in den effektiven Organisations-/Arbeitsbereichseinstellungen und erfordern keine Automatisierungsregel.
schedule.conflict_detectedist der Übergang von keinen Planungskonflikten zu mindestens einem.cardIdnennt den Abhängigen,blockerCardIdnennt seine schlimmste widersprüchliche Voraussetzung unddaysist die Anzahl der Arbeitstage von Montag bis Freitag, die der Angehörige benötigen würde, um richtig umzuziehen. Durch das Hinzufügen eines weiteren Konflikts wird dieser nicht wiederholt.schedule.conflict_resolvedbedeutet, dass eine offene Karte keine Konflikte mehr aufweist, beispielsweise nachdem sich Daten geändert haben, ein Blocker abgeschlossen wurde oder eine Abhängigkeit entfernt wurde. Das Löschen nur eines von mehreren Konflikten löst ihn nicht aus. Ein späteres Wiederauftreten kann die Erkennung erneut auslösen.schedule.critical_path_slippederfordert, dass sowohl das geplante Ende einer kritischen Karte später verschoben wird als auch das geplante Ende des Spielbretts später verschoben wird. Eine durch Slack übernommene Datumsänderung ist nicht qualifiziert, ebenso wenig wie das bloße Hinzufügen neuer Arbeiten.daysmisst, wie weit sich die Projektion bewegt hat;slipDaysmisst seine Verspätung anhand des spätesten Fälligkeitsdatums. Eine Projektion kann sich später verschiebenslipDaysbleibt Null.
Bei der anfänglichen Zeitplanbewertung wird eine Basislinie erstellt, anstatt alle bestehenden Konflikte anzukündigen. Ereignisse melden nachfolgende Grenzen; verwenden work.schedule für den aktuellen Stand beim Starten einer Wache oder bei der Wiederherstellung nach versäumten Lieferungen. Lesen Sie es bei einer Veranstaltung noch einmal durch, bevor Sie Änderungen vorschlagen. Durch diese Warnungen werden Karten nicht neu geplant.
Für einen benutzerdefinierten Host abonnieren Sie jeden Veranstaltungsnamen separat. Diese Anfrage überwacht erste Konflikte auf einem Board; Ersetzen Sie die tatsächlichen Workspace- und Board-UUIDs sowie den verifizierten Rückruf und das Signaturgeheimnis des Hosts:
{
"jsonrpc": "2.0",
"id": 3,
"method": "events/subscribe",
"params": {
"name": "schedule.conflict_detected",
"arguments": { "workspaceId": "…", "boardId": "…" },
"delivery": {
"mode": "webhook",
"url": "https://receiver.example.com/kanera/events",
"secret": "whsec_…"
},
"ttlMs": 86400000
}
}
Ein kritischer Pfadschlupf sieht folgendermaßen aus (IDs und Daten dienen der Veranschaulichung):
{
"eventId": "evt_…_schedule.critical_path_slipped",
"name": "schedule.critical_path_slipped",
"timestamp": "2026-11-02T10:00:00.000Z",
"data": {
"workspaceId": "…",
"boardId": "…",
"cardId": "…",
"previousProjectedFinish": "2026-11-06",
"projectedFinish": "2026-11-09",
"days": 1,
"slipDays": 1,
"actor": { "kind": "user", "userId": "…", "self": false }
},
"cursor": null
}
Termine sind YYYY-MM-DD; Dauer, Pufferzeit und Slip-Anzahl schließen Wochenenden aus. Karten- und Zeitplanereignisse beschreiben möglicherweise dieselbe zugrunde liegende Bearbeitung, haben jedoch unterschiedliche Ereignis-IDs. Wiederholungsversuche deduplizieren durch eventId und prüfen actor.self bevor Sie auf Ihre eigenen Änderungen reagieren. Siehe Planungsbeispiele.
Ihre nächste Warteschlange
priorities.changed teilt einem Agenten mit, dass sich die Up-Next-Warteschlange des verbundenen Benutzers möglicherweise geändert hat, sodass er die Warteschlange erneut lesen kann, anstatt sie abzufragen. Es wird bei jeder Änderung ausgelöst, die die Warteschlange neu anordnet oder ihre Größe ändert:
- ein Eintrag wird hinzugefügt, verschoben oder entfernt, sei es von der Web-App, der API oder einem anderen Agenten;
- Eine in der Warteschlange befindliche Karte wird vervollständigt, archiviert, wiederhergestellt oder neu zugewiesen, wodurch sie aus der Live-Warteschlange entfernt oder wieder zurückgestellt wird.
Es werden keine Argumente benötigt (pass {}) und ist niemals auf einen Arbeitsbereich beschränkt, da sich die Warteschlange über jeden Arbeitsbereich erstreckt, in dem Sie arbeiten. Das Vorkommen trägt nur denjenigen, der es geändert hat:
"data": {
"targetUserId": "…",
"actor": { "kind": "user", "userId": "…", "self": false }
}
targetUserId ist immer der verbundene Benutzer. Es ist nichts über die Karten der Warteschlange enthalten. Rufen Sie an priorities.list für das aktuelle Ranking; Es wird Ihre normale Kartensichtbarkeit angewendet.
Man kann nur zuschauen dein eigenes Warteschlange. Es gibt kein Argument für die einer anderen Person, und das gilt auch für Workspace-Administratoren, die die Warteschlange eines Teamkollegen mitlesen können priorities.list. Selbst eine Benachrichtigung ohne Inhalt würde verraten, wann und von wem eine Karte, die der Beobachter nicht sehen kann, fertiggestellt oder neu zugewiesen wurde. Ein Gast oder ein schreibgeschützter API-Schlüssel kann auch seine eigene Warteschlange überwachen.
Ihr morgendliches Briefing
my_day.ready ermöglicht es einem Agenten, Sie jeden Arbeitsmorgen ohne eigenen Planer zu informieren. Kanera sendet es einmal täglich, Montag bis Freitag, um 08:00 Uhr in der Zeitzone Ihres Profils, zur gleichen Zeit wie die Tägliche Digest-E-Mail. Es folgt der Einstellung des Digests: Während Ihre tägliche Digest-E-Mail deaktiviert ist, wird kein Ping gesendet. Es wird gesendet, unabhängig davon, ob etwas fällig ist oder nicht, sodass der Agent immer noch einen klaren Tag melden kann.
Es werden keine Argumente benötigt (pass {}) und beschreibt immer nur den eigenen Tag. Das Vorkommen trägt keine Arbeit:
"data": {
"targetUserId": "…",
"localDate": "2026-10-12",
"timeZone": "Europe/London",
"actor": { "kind": "system", "userId": null, "self": false }
}
Der Agent ruft dann an work.my_day damit timeZone. Mit nur einem Anruf werden Ihre überfälligen Karten, Karten, die in den nächsten sieben Tagen fällig sind, Karten mit überfälligen Checklistenelementen, zugewiesene Karten, die 14 Tage oder länger inaktiv waren, und die obersten Karten Ihrer „Nächstes Mal“-Warteschlange zurückgegeben, alles mit Ihrem aktuellen Zugriff abgeglichen.
Das Briefing kehrt ebenfalls zurück schedule.conflicts, schedule.critical, und schedule.lateToStart: Ihre zugewiesenen Karten mit Konflikten, Karten mit kritischem Pfad ohne Konflikte und Karten, deren geplanter Start verlief, ohne dass jemals ein Fortschritt eintrat. Spätstartprüfungen erfordern eine Nachverfolgung der Bearbeitungszeit und eine Liste „In Bearbeitung“ und schließen bereits überfällige Karten aus.
Ein Abonnement dauert bis zu 24 Stunden pro Aktualisierung, daher muss der Client es ständig aktualisieren, um den Ping am nächsten Morgen zu erhalten. ChatGPT führt dies aus, während die Aufgabe aktiv ist.
Ihre Kartenerinnerungen
reminder.due lässt einen Agenten handeln, wenn einer Ihrer Kartenerinnerungen wird ausgelöst, um beispielsweise die Karte in einem Chat zu posten oder mit der Arbeit daran zu beginnen. Erinnerungen werden über die Alarmtaste der Karte oder von einem Mitarbeiter eingestellt cards.set_reminder. Es werden keine Argumente benötigt (pass {}) und deckt immer nur Ihre eigenen Mahnungen ab; Niemand kann die eines anderen abonnieren.
Kanera prüft alle 30 Sekunden, ob fällige Erinnerungen vorliegen, und sendet ein Ereignis pro Erinnerung. Durch das Umplanen einer Erinnerung, die bereits abgefeuert wurde, wird sie erneut aktiviert, und beim nächsten Abfeuern handelt es sich um ein neues Ereignis. Das Vorkommen benennt die Karte, trägt aber nichts von ihrem Inhalt:
"data": {
"targetUserId": "…",
"reminderId": "…",
"cardId": "…",
"remindAt": "2026-10-16T07:00:00.000Z",
"url": "https://board.kanera.app/o/…/c/MKT-42",
"actor": { "kind": "system", "userId": null, "self": false }
}
Der Agent ruft an cards.get mit dem cardId für die aktuelle Karte. Die Lieferung prüft, ob Sie die Karte noch sehen können. Eine Erinnerung an eine Karte, die inzwischen archiviert wurde oder auf die Sie nicht mehr zugreifen können, wird ohne Benachrichtigung oder Ereignis ausgelöst.
Beobachten Sie die Arbeit für Änderungen in ChatGPT
Installieren und verbinden Sie das Kanera-Plugin mit dem ChatGPT-Einrichtungsanleitungund wählen Sie es dann in einer Arbeitskonversation aus, die ereignisgesteuerte Aufgaben unterstützt. Ein kompatibler Host erkennt die Ereignisfunktion automatisch. Öffnen Sie eine benutzerdefinierte MCP-Verbindung in Plugins und auswählen Aktualisieren nach Serverwechseln. Veröffentlichte Plugin-Tool-Updates folgen dem Überprüfungsprozess von OpenAI.
Fragen Sie in einem Gespräch, an das die Kanera-App angeschlossen ist, nach dem, was passieren soll:
Watch the Product board in Kanera. When a new comment appears on any card, summarise it for me and suggest a reply.
Tell me whenever a card moves into the Done list on the Launch board.
Whenever my Up next queue changes, tell me what is now at the top.
Every weekday morning, brief me on what is overdue, what is due this week, and what is at the top of my Up next queue.
Watch the Launch board for scheduling conflicts and critical-path slips. Read the current schedule when one appears, tell me which cards and dates are affected, and propose a repair. Tell me when conflicts clear. Do not change dates.
ChatGPT erstellt das Abonnement für seinen eigenen gehosteten Rückruf, aktualisiert es, während die Aufgabe aktiv ist, und beendet es, wenn Sie die Aufgabe stoppen. Kanera sendet Ihre Arbeit niemals irgendwohin. ChatGPT hat nicht nachgewiesen, dass es die Kontrolle hat (siehe Rückrufbestätigung).
Weitere praktische Beispiele, darunter die Beantwortung von Fragen zu Karten, die Auswahl neuer Arbeiten und die Bewachung einer einzelnen Karte, finden Sie hier Anwendungsbeispiele.
Zwei Dinge, die Sie beim Schreiben der Aufgabe wissen sollten:
- Vermeiden Sie Schleifen. Jedes Vorkommnis nennt seinen Akteur und gibt an, ob die abonnierende Verbindung es verursacht hat. Eine Aufgabe, die auf Kommentare durch Kommentieren reagiert, sollte prüfen
actor.selfbevor Sie erneut schreiben, sonst antwortet es von selbst. - Lesen Sie, bevor Sie schreiben. Das Vorkommen ist eine Zusammenfassung. Bitten Sie die Aufgabe, zuerst die Karte zu lesen und die Idempotenzschlüssel der Tools für wiederholbare Änderungen zu verwenden.
Die Zustellung erfolgt nach dem Best-Effort-Prinzip mit einem begrenzten Wiederholungsfenster (siehe Zustellung und Wiederholungsversuche). Wenn der Rückruf von ChatGPT länger nicht erreichbar ist, wird das Vorkommnis übersehen; Die Aufgabe wird wiederhergestellt, indem sie den aktuellen Status liest.
Das Protokoll
Ereignisse sind nur auf dem gehosteten HTTP-Endpunkt verfügbar. https://mcp.kanera.app/mcp oder Ihre eigene Bereitstellung /mcpund nur für Clients mit dem aktuellen MCP-Protokoll, wodurch Ereignisabonnements hinzugefügt werden. kanera mcp over stdio bietet sie nicht an: Ein lokaler stdio-Host hat keinen gehosteten Rückruf, an den er zustellen kann.
server/discover bewirbt die Fähigkeit unter beiden capabilities.events (was ChatGPT heute liest) und capabilities.extensions["io.modelcontextprotocol/events"] (wo der Erweiterungsvorschlag es platziert). Es folgen drei Anforderungsmethoden, die genau wie Toolaufrufe authentifiziert werden und über ein OAuth-Zugriffstoken oder einen API-Schlüssel als Träger verfügen. Die folgenden Beispiele zeigen nur die Methodenparameter; Die Client-Bibliothek fügt die Header und Metadaten des Protokolls pro Anforderung hinzu.
events/list
Gibt den obigen Katalog mit einem JSON-Schema für die Argumente und Nutzdaten jedes Ereignisses zurück. Der Katalog besteht aus einer einzigen Seite; cursor muss fehlen oder leer sein.
{
"jsonrpc": "2.0",
"id": 1,
"method": "events/list",
"params": {}
}
events/subscribe
{
"jsonrpc": "2.0",
"id": 2,
"method": "events/subscribe",
"params": {
"name": "comment.created",
"arguments": { "workspaceId": "…", "boardId": "…" },
"delivery": {
"mode": "webhook",
"url": "https://receiver.example.com/kanera/events",
"secret": "whsec_…"
},
"ttlMs": 86400000
}
}
| Feld | Regeln |
|---|---|
delivery.mode | Nur webhook wird unterstützt. Jeder andere Modus kehrt zurück -32014 Unsupported mit data.feature = "deliveryMode". |
delivery.url | HTTPS, keine Anmeldeinformationen in der URL, kein Fragment und die Auflösung muss in eine öffentliche Adresse erfolgen. Loopback-, private, Link-Local-, Cloud-Metadaten- und IPv4-zugeordnete oder Übergangs-IPv6-Adressen werden abgelehnt. |
delivery.secret | whsec_ gefolgt von 24 bis 64 Byte Base64. Kanera speichert es verschlüsselt und signiert jede Lieferung damit. |
ttlMs | Angeforderte Lebensdauer. Der Standardwert und das Maximum betragen 24 Stunden; ein kürzerer positiver Wert wird berücksichtigt, und null (kein Ablauf) ist auf 24 Stunden begrenzt. |
cursor, maxAgeMs | Aus Kompatibilitätsgründen akzeptiert. Kanera bietet keine Wiederholung an: cursor wird immer zurückgegeben als null, und ein Anforderungscursor ungleich Null wird als gemeldet truncated: true. |
Die Antwort:
{
"id": "sub_…",
"refreshBefore": "2026-10-07T13:00:00.000Z",
"cursor": null,
"truncated": false,
"deliveryStatus": {
"active": true,
"lastDeliveryAt": "2026-10-06T12:58:10.000Z",
"lastError": null
}
}
Das Abonnement id ist deterministisch für die Verbindung, die Rückruf-URL, den Ereignisnamen und die Argumente (z priorities.changed, my_day.ready, und reminder.due, der verbundene Benutzer), also Aufruf events/subscribe wieder mit der gleichen Identität ist a auffrischen: es erstreckt sich refreshBefore, akzeptiert ein neues secret (sowohl das alte als auch das neue Geheimzeichen liefert fünf Minuten lang) und kehrt zurück deliveryStatus für ein noch aktives Abonnement. deliveryStatus entfällt bei einem Erstabonnement und bei einer Verlängerung nach Ablauf. Vorher aktualisieren refreshBefore; Ein abgelaufenes Abonnement, das später verlängert wird, beginnt mit dem Verlängerungszeitpunkt neu, ohne dass das verpasste Abonnement wiederholt wird.
active ist immer true: Kanera setzt ein Abonnement niemals wegen Lieferfehlern aus. Stattdessen werden die Wiederholungsversuche pro Vorkommen begrenzt und der Zustand des Endpunkts gemeldet lastError (einer von connection_refused, timeout, tls_error, http_4xx, http_5xx, challenge_failed) und failedSince, vorhanden, während der Endpunkt weiterhin ausfällt.
Eine Verbindung kann bis zu 100 aktive Abonnements enthalten. Der 101. kehrt zurück -32013 ResourceExhausted.
events/unsubscribe
Nimmt das Gleiche name, arguments, und delivery.url, ohne Geheimnis. Nur die Verbindung, die ein Abonnement erstellt hat, kann es beenden; Die Anfrage eines anderen Berechtigungsnachweises ist ein No-Op. Das Abbestellen ist idempotent.
Fehler
Kanera verwendet die Fehlercodes der Entwurfsdokumente für Ereignisse. Abonnementfehler werden strukturiert durchgeführt data sodass ein Host darauf reagieren kann, ohne Nachrichten zu analysieren.
| Code | Name | Wann |
|---|---|---|
-32011 | NotFound | name ist nicht im Katalog (data.kind = "event"). |
-32012 | Forbidden | Die Identität kann den angeforderten Bereich nicht sehen oder die Anmeldeinformationen sind kein API-Schlüssel oder keine OAuth-Verbindung. |
-32013 | ResourceExhausted | Das Abonnementlimit (data.max) oder eine Tarifbegrenzung. |
-32014 | Unsupported | Ein anderer Liefermodus als webhook (data.feature, data.value). |
-32015 | CallbackEndpointError | Die Überprüfung ist fehlgeschlagen. data.reason ist einer von connection_refused, timeout, tls_error, http_4xx, http_5xx, oder challenge_failed. Ein abgelehntes Ziel wird als gemeldet challenge_failedDaher können Fehlerantworten nicht zur Zuordnung eines privaten Netzwerks verwendet werden. |
-32602 | InvalidParams | Eine fehlerhafte Anfrage, ein ungültiges Geheimnis oder eine ungültige URL, ein Arbeitsbereich, ein Board oder eine Karte arguments das nicht existiert, oder irgendein Argument, an das übergeben wird priorities.changed, my_day.ready, oder reminder.due. |
Rückrufbestätigung
Bevor ein Abonnement gespeichert wird, weist Kanera nach, dass der Rückruf Ihnen gehört. Es sendet eine Verifizierungsanfrage an delivery.url, signiert mit dem von Ihnen angegebenen Geheimnis:
{ "type": "verification", "challenge": "…" }
Der Endpunkt muss antworten 2xx mit einem JSON-Body, der die Herausforderung genau wiedergibt:
{ "challenge": "…" }
Alles andere schlägt beim Abonnieren fehl -32015 und der Grund oben. Weiterleitungen werden niemals befolgt. Eine erfolgreiche Verifizierung wird für fünf Minuten pro Verbindung und Rückruf-URL zwischengespeichert, also aktualisiert oder variiert arguments wiederholt die Herausforderung nicht.
Die Verifizierung läuft mit der gleichen strengen Zielrichtlinie wie die Zustellung: nur öffentliche HTTPS-Adressen, einmal aufgelöst und für die Verbindung fixiert, sodass eine DNS-Änderung zwischen der Prüfung und der Anfrage sie nicht umleiten kann.
Zustellung und Wiederholungsversuche
Jedes Vorkommen ist eins POST zum Rückruf mit Content-Type: application/json:
{
"eventId": "evt_…",
"name": "comment.created",
"timestamp": "2026-10-06T12:58:09.412Z",
"data": {
"workspaceId": "…",
"boardId": "…",
"cardId": "…",
"commentId": "…",
"text": "Can we ship this on Thursday?",
"url": "https://board.kanera.app/o/3F2A9C1D7B4E6A08/c/PROJ-123",
"actor": { "kind": "user", "userId": "…", "self": false }
},
"cursor": null
}
| Kopfzeile | Inhalt |
|---|---|
webhook-id | Die eventId. Stabil über Wiederholungsversuche hinweg; Verwenden Sie es, um den Handler idempotent zu machen. |
webhook-timestamp | Unix-Sekunden, als dieser Versuch signiert wurde. Bei jedem erneuten Versuch frisch. |
webhook-signature | Ein oder mehrere durch Leerzeichen getrennte v1,<base64> Unterschriften (zwei während einer geheimen Rotation). |
X-MCP-Subscription-Id | Das Abonnement id. |
Die Body-Bytes sind bei jedem Versuch identisch; Lediglich der Zeitstempel und die Signatur ändern sich.
Reagieren Sie 2xx anerkennen. Kanera behandelt Antworten wie folgt:
| Antwort | Verhalten |
|---|---|
2xx | Geliefert. Der Körper wird ignoriert. |
410, 413, und andere 4xx | Dieses Vorkommen wird gelöscht. Das Abonnement läuft weiter; Zukünftige Ereignisse werden weiterhin geliefert. |
408, 425, 429, 5xx, Timeout, TLS oder Verbindungsfehler | Habe es mit dem Gleichen noch einmal versucht eventId: insgesamt fünf Versuche mit ungefähr 0 s, 30 s, 1,5 min, 3,5 min und 7,5 min. Danach wird das Vorkommen gelöscht. |
Ein Antworttext mit mehr als 4 KiB wird verworfen, ohne das Ergebnis zu beeinflussen. Ein Vorkommen über 256 KiB wird nie gesendet. Kanera bewahrt die Lieferaufzeichnungen 14 Tage lang auf.
Lieferungen für ein aktives Abonnement überdauern Kanera-Neustarts. Die Autorisierung wird vor jedem Versuch erneut überprüft, sodass ein getrennter Agent, ein widerrufener Schlüssel, ein entferntes Mitglied oder ein Gast, der eine Zuweisung verloren hat, beim nächsten Versuch keine Daten mehr empfangen, nicht bei der nächsten Aktualisierung.
priorities.changed Vorkommnisse werden in dem Moment in die Warteschlange gestellt, in dem die Warteschlangenänderung gespeichert wird, und nicht aus dem dauerhaften Änderungsprotokoll, das Kartenereignisse verwenden, da die Warteschlange nicht an einen einzelnen Arbeitsbereich gebunden ist. In dem seltenen Fall, dass Kanera in diesem Moment neu startet, kann eine Benachrichtigung verloren gehen; der nächste priorities.list read ist immer aktuell.
Überprüfen Sie die Signatur
Das Schema ist das Standard-Webhooks Layout. Entschlüsseln Sie das Geheimnis nach dem whsec_ Präfix von Base64, HMAC-SHA256 der Zeichenfolge {webhook-id}.{webhook-timestamp}.{body}und mit jeder Signatur im Header in konstanter Zeit vergleichen:
import crypto from "node:crypto";
import express from "express";
const app = express();
const key = Buffer.from(process.env.KANERA_MCP_EVENT_SECRET!.slice("whsec_".length), "base64");
app.post("/kanera/events", express.raw({ type: "application/json" }), (req, res) => {
const body = req.body.toString("utf8");
const payload = JSON.parse(body) as { type?: string; challenge?: string };
const id = req.header("webhook-id") ?? "";
const timestamp = req.header("webhook-timestamp") ?? "";
const expected = crypto.createHmac("sha256", key).update(`${id}.${timestamp}.${body}`).digest("base64");
const digest = Buffer.from(expected);
const valid = (req.header("webhook-signature") ?? "").split(" ").some((entry) => {
const received = Buffer.from(entry.replace(/^v1,/, ""));
return received.length === digest.length && crypto.timingSafeEqual(received, digest);
});
if (!valid) return res.status(401).send("invalid signature");
// Verification challenge: echo it back.
if (payload.type === "verification") return res.json({ challenge: payload.challenge });
// Occurrence: handle it idempotently by webhook-id.
res.sendStatus(204);
});
Überprüfen Sie immer anhand des Rohkörpers. Lieferungen ablehnen, deren webhook-timestamp Bis zur gebundenen Wiederholung sind es nur noch mehr als ein paar Minuten.
Erzählen Sie Ihre eigenen Texte auseinander
Ein Agent, der auf Ereignisse reagiert, indem er zurückschreibt, wird feststellen, dass seine eigenen Schreibvorgänge als Ereignisse eintreten. userId allein kann sie nicht trennen: Ein persönlicher API-Schlüssel oder ein OAuth-Agent fungiert als sein Benutzer, sodass ein Kommentar, den der Agent gepostet hat, und ein Kommentar, den die Person gepostet hat, dasselbe haben userId.
Zu jedem Vorkommnis gehören daher:
"actor": { "kind": "apiKey", "userId": "…", "self": true }
| Feld | Bedeutung |
|---|---|
kind | user (die Web-App), apiKey, agent (ein interaktiver OAuth-Agent), support, automation, oder system. |
userId | Der Benutzer, als der die Änderung vorgenommen wurde. null für Automatisierung und Systemänderungen. |
self | true Nur wenn die abonnierende Verbindung selbst die Änderung vorgenommen hat: dieselbe OAuth-Agent-Gewährung, derselbe direkt verwendete API-Schlüssel oder dieselbe unbeaufsichtigte Dienstverbindung. |
Automatisierungseffekte werden als gemeldet automation Selbst wenn sie durch den eigenen Schreibvorgang des Agenten ausgelöst wurden, wird eine Regel, die nach den Kommentaren des Agenten eine Bezeichnung hinzufügt, nicht als Schreibvorgang des Agenten gelesen.
Die title und text Felder sind Benutzerinhalte. Behandeln Sie sie als Daten, niemals als Anweisungen an den Agenten.
Direktes Aufrufen derselben API
Die MCP-Methoden leiten an drei öffentliche API-Routen weiter, die dieselben Inhaberanmeldeinformationen und dieselben Anforderungs- und Antworttexte akzeptieren. Verwenden Sie sie aus einer Integration, die über einen API-Schlüssel verfügt und Ereignisabonnements ohne MCP-Sprache wünscht:
| Route | MCP-Methode |
|---|---|
GET /api/v1/mcp-events | events/list |
POST /api/v1/mcp-events/subscribe | events/subscribe |
POST /api/v1/mcp-events/unsubscribe | events/unsubscribe |
Fehler werden als öffentliche API-Problemdokumente mit den Codes zurückgegeben MCP_EVENT_NOT_FOUND, MCP_EVENT_UNSUPPORTED, MCP_SUBSCRIPTION_LIMIT, und MCP_CALLBACK_ENDPOINT, die die MCP-Schicht auf die obige Fehlertabelle abbildet.
Für eine Teamintegration, die jede einzelne Verbindung überdauern und den gesamten Veranstaltungskatalog abdecken sollte, verwenden Sie Webhooks stattdessen. MCP-Ereignisabonnements gehören zu den Anmeldeinformationen, mit denen sie erstellt wurden, laufen innerhalb von 24 Stunden ab, sofern sie nicht aktualisiert werden, und decken nur die vier Karten- und Kommentarereignisse sowie Ihre eigene Up-Next-Warteschlange ab. Webhooks liefern keine Up next-Änderungen, da es sich bei der Warteschlange um persönliche und nicht um Arbeitsbereichsdaten handelt.
Fehlerbehebung
| Problem | Was zu überprüfen ist |
|---|---|
| Der Auftraggeber bietet keine Veranstaltungen an. | Es muss eine Verbindung zum gehosteten Server hergestellt werden /mcp Endpunkt auf dem aktuellen MCP-Protokoll. Scannen Sie den Server im Client erneut. stdio via kanera mcp bietet niemals Veranstaltungen an. |
events/subscribe kehrt zurück -32015 mit challenge_failed. | Der Rückruf hat die Aufforderung nicht widergespiegelt, einen Nicht-2xx-Status beantwortet, wurde umgeleitet oder befindet sich auf einer privaten Adresse, einer Loopback-Adresse oder einer Metadatenadresse. Kanera berichtet dies alles bewusst auf die gleiche Weise. |
-32012 Forbidden auf abonnieren. | Die Identität kann den Arbeitsbereich, das Board oder die Karte nicht sehen. Bordgäste müssen passieren boardId; Gäste, die nur mit zugewiesenen Gegenständen ausgestattet sind, müssen eine zugewiesene Prüfung bestehen cardId. Sitzungscookies können nicht abonniert werden; Verwenden Sie eine OAuth-Verbindung oder einen API-Schlüssel. |
| Die Lieferungen wurden gestoppt, aber das Abonnement wird weiterhin aktualisiert. | Überprüfen deliveryStatus.lastError und failedSince auf die Aktualisierungsantwort. Wenn die Anmeldeinformationen widerrufen wurden oder der Benutzer den Zugriff verloren hat, ist das Abonnement abgelaufen und die Aktualisierung gibt „Nein“ zurück deliveryStatus. |
| Der Agent reagiert ständig auf seine eigenen Kommentare. | Überprüfen data.actor.self vor dem Schreiben. |
-32602 beim Abonnieren priorities.changed. | Leer passieren arguments. A targetUserId oder jedes andere Argument wird abgelehnt: Nur Ihre eigene Warteschlange kann überwacht werden. |
| Verpasste Änderungen nach einem Ausfall. | Wiederholungsversuche werden nach etwa 7,5 Minuten beendet und es erfolgt keine Wiederholung. Lesen Sie den aktuellen Status mit cards.list, cards.get, comments.list, oder priorities.list. |