Ga naar de hoofdinhoud

Abonneer u op evenementen via MCP

Een AI-agent die via MCP met Kanera is verbonden, kan vragen om te worden geïnformeerd wanneer werk verandert, in plaats van te pollen. Kanera implementeert de webhooklevering van het concept MCP-evenementen extensie: de host van de agent registreert een HTTPS-callback, Kanera verifieert deze en vanaf dat moment wordt elke overeenkomende wijziging ernaar gepost als een ondertekende JSON-exemplaar.

Dit is het mechanisme achter "bekijk dit bord en vertel me wanneer er een reactie binnenkomt" in een client zoals ChatGPT. De host is eigenaar van de callback; u voert geen server uit en plakt nergens een URL in Kanera.

Voor wie is dit bedoeld Als u ChatGPT gebruikt, lees dan Houd het werk in de gaten voor wijzigingen in ChatGPT en stop daar. De rest van deze pagina is het wire-level contract voor mensen die hun eigen MCP-host of een aangepaste integratie bouwen, en voor iedereen die precies wil weten wat een agent wel en niet kan worden verteld. :::

Waar een agent zich op kan abonneren​

EvenementBrandt wanneerExtra velden binnen data
card.createdEr wordt een kaart aangemaakt in het bewaakte bereik.title, listId, url
card.updatedEen kaart verandert: titel, beschrijving, voltooiing, archiefstatus en andere kaartvelden.title, listId, url
card.movedEen kaart beweegt binnen of tussen lijsten of borden.listId (de bestemming), fromListId (de bron), prevPosition, url
card.blockedEen actieve kaart krijgt zijn eerste open blocker, inclusief heropening of herstel.title, listId, url; geen blockerdetails
card.unblockedEen actieve kaart verliest zijn laatste open blokkering door voltooiing, archivering, ontkoppeling of verwijdering van het bord of de lijst van de blokkering.title, listId, url; geen blockerdetails
schedule.conflict_detectedEen open kaart krijgt zijn eerste planningsconflict: een open blokkering is gepland om op of na de start te eindigen.blockerCardId, days (werkdagen waarop de afhankelijke persoon moet verhuizen)
schedule.conflict_resolvedEen open kaart verliest het laatste planningsconflict.Geen extra planningsvelden
schedule.critical_path_slippedHet geplande einde van een kaart met een kritiek pad wordt later verplaatst en vertraagt de verwachte voltooiing van het bord.previousProjectedFinish, projectedFinish, days, slipDays
comment.createdEr wordt een opmerking op een kaart geplaatst.commentId, text (tot 8.000 tekens), url
priorities.changedJouw eigen Hierna wachtrij is mogelijk gewijzigd.Geen. Zie Je volgende wachtrij.
my_day.readyHet is een doordeweekse ochtend in uw tijdzone.localDate, timeZone. Zie Je ochtendbriefing.
reminder.dueEén van jezelf kaartherinneringen komt op tijd.reminderId, cardId, remindAt, url. Zie Uw kaartherinneringen.

Elke kaart- en commentaargebeurtenis draagt een waarde met zich mee workspaceId, boardId, cardId, en een actor (zie Het vertellen van je eigen schrijft apart). Payloads zijn begrensde samenvattingen: de beschrijving, bijlagen en volledige commentaarthread van een kaart zijn nooit opgenomen. De agent leest het huidige record met cards.get of comments.list wanneer er meer nodig is.

Voor kaart-, commentaar- en planningsevenementen: abonnement argumenten smal wat geleverd wordt:

ArgumentVereistEffect
workspaceIdJaAlleen gebeurtenissen in deze werkruimte.
boardIdNeeAlleen evenementen op dit bord. Verplicht voor boardgasten.
listIdNeeAlleen gebeurtenissen voor kaarten in deze werkruimtelijst. Voor card.moved, een kaart die de lijst binnenkomt of verlaat, komt overeen en herschikkingen daarin niet. Laat weg boardId om de gedeelde lijst op elk toegankelijk bord te bekijken.
cardIdNeeAlleen evenementen voor deze kaart. Vereist boardId.

Toegang volgt de verbonden identiteit bij elke levering, niet alleen tijdens het abonnement. Een lid van de werkruimte kan de hele werkruimte bekijken; een gast uit meerdere organisaties moet een bord noemen waarvoor hij of zij is uitgenodigd; een gast die beperkt is tot toegewezen items, moet een kaart noemen waaraan hij momenteel is toegewezen. Als de identiteit later de toegang tot het bereik verliest, stopt de levering en verloopt het abonnement. Als u de toegang tot één kaart binnen een bordbreed abonnement verliest, wordt alleen dat voorval overgeslagen.

Afhankelijkheidsovergangen​

card.blocked en card.unblocked volgen kaart afhankelijkheden, inclusief wijzigingen van mensen, integraties, automatiseringen en gespiegelde kaarten. Ze vereisen geen automatiseringsregel. Door nog een blokkering toe te voegen of slechts één van meerdere blokkeringen op te heffen, wordt de overgang niet herhaald. Elke richting is beperkt tot één keer per kaart per transactie.

De gebeurtenis beschrijft de afhankelijke kaart en laat de blokkeringsgegevens weg om privéborden te beschermen. Lees cards.get voor de huidige relaties die zichtbaar zijn voor uw verbinding. Controleer de huidige status voordat u handelt, omdat een automatisering de kaart mogelijk al heeft verplaatst of voltooid.

Plan overgangen​

De drie schedule.* evenementen gebruiken dezelfde werkdagengine als de Tijdlijnweergave en work.schedule. Ze vereisen dat Tijdlijn en afhankelijkheden zijn ingeschakeld in de effectieve organisatie-/werkruimte-instellingen, en vereisen geen automatiseringsregel.

  • schedule.conflict_detected is de overgang van geen planningsconflicten naar ten minste één. cardId noemt de afhankelijke, blockerCardId noemt de ergste tegenstrijdige voorwaarde, en days is het aantal werkdagen van maandag tot en met vrijdag dat de afhankelijke persoon nodig heeft om naar rechts te gaan. Het toevoegen van nog een conflict herhaalt het niet.
  • schedule.conflict_resolved betekent dat een open kaart geen conflicten meer heeft, bijvoorbeeld nadat datums zijn gewijzigd, een blokkering is voltooid of een afhankelijkheid is verwijderd. Als u slechts één van de verschillende conflicten oplost, wordt deze niet geactiveerd. Een latere herhaling kan de detectie opnieuw activeren.
  • schedule.critical_path_slipped vereist dat zowel het geplande einde van een kritieke kaart later wordt verplaatst als de verwachte finish van het bord om later te worden verplaatst. Een datumwijziging die door speling wordt geabsorbeerd, komt niet in aanmerking, net zo min als het louter toevoegen van nieuw werk. days meet hoe ver de projectie bewoog; slipDays meet de laattijdigheid af tegen de laatste vervaldatum. Een projectie kan later bewegen slipDays blijft nul.

De initiële planningsevaluatie stelt een basislijn vast in plaats van alle bestaande conflicten aan te kondigen. Gebeurtenissen rapporteren daaropvolgende grenzen; gebruik work.schedule voor de huidige status bij het starten van een wacht of bij het herstellen van gemiste leveringen. Lees het opnieuw tijdens een evenement voordat u wijzigingen voorstelt. Met deze waarschuwingen worden kaarten niet opnieuw gepland.

Voor een aangepaste host moet u zich afzonderlijk op elke evenementnaam abonneren. Met dit verzoek worden de eerste conflicten op één bord bekeken; vervang de werkelijke werkruimte en board-UUID's en het geverifieerde callback- en ondertekeningsgeheim van de host:

{
"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
}
}

Een slip op een kritiek pad ziet er als volgt uit (ID's en datums zijn ter illustratie):

{
"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
}

Datums zijn YYYY-MM-DD; duur, speling en sliptellingen zijn exclusief weekenden. Kaart- en planningsgebeurtenissen kunnen dezelfde onderliggende bewerking beschrijven, maar hebben verschillende gebeurtenis-ID's. Ontdubbel nieuwe pogingen door eventId en controleer actor.self voordat u op uw eigen veranderingen reageert. Zie voorbeelden van plannen.

Je volgende wachtrij​

priorities.changed vertelt een agent dat de eigen Up next-wachtrij van de verbonden gebruiker mogelijk is gewijzigd, zodat deze de wachtrij opnieuw kan lezen in plaats van te pollen. Het wordt geactiveerd bij elke wijziging die de wachtrij opnieuw rangschikt of de grootte ervan wijzigt:

  • er wordt een item toegevoegd, verplaatst of verwijderd, hetzij vanuit de webapp, de API of een andere agent;
  • een kaart in de wachtrij wordt voltooid, gearchiveerd, hersteld of opnieuw toegewezen, waardoor deze uit de live wachtrij wordt gehaald of teruggeplaatst.

Er zijn geen argumenten nodig (pass {}) en is nooit gericht op een werkruimte, omdat de wachtrij elke werkruimte omvat waarin u werkt. De instance vermeldt alleen wie deze heeft gewijzigd:

"data": {
"targetUserId": "…",
"actor": { "kind": "user", "userId": "…", "self": false }
}

targetUserId is altijd de verbonden gebruiker. Er is niets opgenomen over de kaarten van de wachtrij. Bel priorities.list voor de huidige ranglijst; het past uw normale kaartzichtbaarheid toe.

Je kunt alleen maar kijken jouw eigen wachtrij. Er is geen argument voor die van iemand anders, en dat geldt ook voor werkruimtebeheerders die de wachtrij van een teamgenoot kunnen lezen priorities.list. Zelfs een melding zonder inhoud zou onthullen wanneer en door wie een kaart die de kijker niet kan zien, is voltooid of opnieuw is toegewezen. Een gast of een alleen-lezen API-sleutel kan ook zijn eigen wachtrij bekijken.

Je ochtendbriefing​

my_day.ready laat een agent u elke werkdag briefen zonder zijn eigen planner. Kanera verzendt het één keer per dag, van maandag tot en met vrijdag, om 08:00 uur in de tijdzone van uw profiel, op dezelfde tijd als de dagelijkse samenvatting van e-mail. Het volgt de instelling van de samenvatting: zolang uw dagelijkse samenvattings-e-mail is uitgeschakeld, wordt er geen ping verzonden. Er wordt verzonden of er wel of niet iets moet gebeuren, zodat de agent alsnog een heldere dag kan melden.

Er zijn geen argumenten nodig (pass {}) en beschrijft alleen je eigen dag. Het voorval levert geen werk op:

"data": {
"targetUserId": "…",
"localDate": "2026-10-12",
"timeZone": "Europe/London",
"actor": { "kind": "system", "userId": null, "self": false }
}

De agent belt dan work.my_day daarmee timeZone. Met één oproep worden uw achterstallige kaarten geretourneerd, kaarten die in de komende zeven dagen vervallen, kaarten met achterstallige checklistitems, toegewezen kaarten die 14 dagen of langer inactief zijn geweest, en de bovenkant van uw Up next-wachtrij, allemaal gecontroleerd aan de hand van uw huidige toegang.

De briefing komt ook terug schedule.conflicts, schedule.critical, en schedule.lateToStart: je toegewezen kaarten met conflicten, kritieke pad-kaarten zonder conflicten, en kaarten waarvan de geplande start voorbij is gegaan zonder ooit voortgang te hebben geboekt. Controles bij late start vereisen het bijhouden van de lopende tijd en een lijst In uitvoering, en sluiten kaarten die al te laat zijn uit.

Een abonnement duurt maximaal 24 uur per vernieuwing, dus de klant moet het blijven vernieuwen om de ping van de volgende ochtend te ontvangen. ChatGPT doet dit terwijl de taak actief is.

Uw kaartherinneringen​

reminder.due laat een agent optreden wanneer een van uw kaartherinneringen branden, bijvoorbeeld om de kaart in een chat te plaatsen of eraan te gaan werken. Herinneringen worden ingesteld via de alarmknop op de kaart of door een agent cards.set_reminder. Er zijn geen argumenten nodig (pass {}) en heeft alleen betrekking op uw eigen herinneringen; niemand kan zich abonneren op die van iemand anders.

Kanera controleert elke 30 seconden of er herinneringen zijn en verzendt één keer per herinnering. Als u een herinnering opnieuw plant die al heeft afgevuurd, wordt deze opnieuw geactiveerd en is het volgende vuur een nieuwe gebeurtenis. De gebeurtenis noemt de kaart, maar bevat niets van de inhoud ervan:

"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 }
}

De agent belt cards.get met de cardId voor de huidige kaart. Leveringscontroles waarbij u de kaart nog kunt zien; een herinnering op een kaart die inmiddels is gearchiveerd of waar u geen toegang meer toe heeft, wordt geactiveerd zonder melding of gebeurtenis.

Houd het werk in de gaten voor wijzigingen in ChatGPT​

Installeer en verbind de Kanera-plug-in met behulp van de ChatGPT-installatiegidsen selecteer het vervolgens in een werkgesprek dat gebeurtenisgestuurde taken ondersteunt. Een compatibele host ontdekt automatisch de evenementenmogelijkheid. Voor een aangepaste MCP-verbinding opent u deze in Plug-ins en selecteer Vernieuwen na serverwijzigingen. Gepubliceerde plug-in tool-updates volgen het beoordelingsproces van OpenAI.

Vraag in een gesprek waaraan de Kanera-app is gekoppeld, wat je wilt dat er gebeurt:

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 maakt het abonnement aan op zijn eigen gehoste callback, vernieuwt het terwijl de taak actief is en beëindigt het wanneer u de taak stopt. Kanera stuurt uw werk nooit ergens heen waarvan ChatGPT niet heeft bewezen dat het de controle heeft (zie Terugbelverificatie).

Meer uitgewerkte voorbeelden, waaronder het beantwoorden van vragen over kaarten, het beoordelen van nieuw werk en het bewaken van een enkele kaart, zijn binnen Voorbeelden van hoe te gebruiken.

Twee dingen die u moet weten bij het schrijven van de taak:

  • Vermijd lussen. Bij elke gebeurtenis wordt de actor genoemd en wordt aangegeven of de abonnementsverbinding dit heeft veroorzaakt. Een taak die op opmerkingen reageert door commentaar te geven, moet controleren actor.self voordat u opnieuw schrijft, anders zal het zichzelf beantwoorden.
  • Lees voordat je schrijft. Het voorval is een samenvatting. Vraag de taak om eerst de kaart te lezen en de idempotentiesleutels van de tools te gebruiken voor herhaalbare wijzigingen.

Levering gebeurt naar beste vermogen met een begrensd venster voor nieuwe pogingen (zie Bezorging en nieuwe pogingen). Als de callback van ChatGPT langer onbereikbaar is, wordt de gebeurtenis gemist; de taak herstelt door de huidige status te lezen.

Het protocol​

Gebeurtenissen zijn alleen beschikbaar op het gehoste HTTP-eindpunt, https://mcp.kanera.app/mcp of die van uw eigen implementatie /mcp, en alleen voor clients met het huidige MCP-protocol, dat is wat gebeurtenisabonnementen toevoegt. kanera mcp over stdio biedt ze niet aan: een lokale stdio-host heeft geen gehoste callback om aan af te leveren.

server/discover adverteert de mogelijkheden onder beide capabilities.events (wat ChatGPT vandaag leest) en capabilities.extensions["io.modelcontextprotocol/events"] (waar het uitbreidingsvoorstel het plaatst). Er volgen drie aanvraagmethoden, die op precies dezelfde manier worden geverifieerd als toolaanroepen, met een OAuth-toegangstoken of een API-sleutel als drager. De onderstaande voorbeelden tonen alleen de methodeparameters; de clientbibliotheek voegt de headers en metagegevens per verzoek van het protocol toe.

events/list​

Retourneert de bovenstaande catalogus met een JSON-schema voor de argumenten en payload van elke gebeurtenis. De catalogus bestaat uit één pagina; cursor moet afwezig of leeg zijn.

{
"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
}
}
VeldRegels
delivery.modeAlleen webhook wordt ondersteund. Elke andere modus keert terug -32014 Unsupported met data.feature = "deliveryMode".
delivery.urlHTTPS, geen inloggegevens in de URL, geen fragment en het moet worden omgezet naar een openbaar adres. Loopback-, privé-, link-local-, cloud-metadata- en IPv4-mapped of transitie-IPv6-adressen worden geweigerd.
delivery.secretwhsec_ gevolgd door 24 tot 64 bytes base64. Kanera slaat het versleuteld op en ondertekent er elke levering mee.
ttlMsGevraagde levensduur. De standaard en het maximum zijn 24 uur; een kortere positieve waarde wordt gehonoreerd, en null (geen vervaldatum) is beperkt tot 24 uur.
cursor, maxAgeMsGeaccepteerd voor compatibiliteit. Kanera biedt geen herhaling: cursor wordt altijd geretourneerd als null, en een niet-null verzoekcursor wordt gerapporteerd als truncated: true.

Het antwoord:

{
"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
}
}

Het abonnement id is deterministisch voor de verbinding, callback-URL, gebeurtenisnaam en argumenten (voor priorities.changed, my_day.ready, en reminder.due, de verbonden gebruiker), dus bellend events/subscribe opnieuw met dezelfde identiteit is a vernieuwen: het breidt zich uit refreshBefore, accepteert een nieuwe secret (zowel de oude als de nieuwe geheime tekenbezorging gedurende vijf minuten), en keert terug deliveryStatus voor een abonnement dat nog actief was. deliveryStatus wordt weggelaten bij een eerste abonnement en bij een verlenging na de vervaldatum. Ververs eerder refreshBefore; een verlopen abonnement dat later wordt verlengd, begint opnieuw vanaf de verlengingstijd, zonder herhaling van wat het heeft gemist.

active is altijd true: Kanera schort nooit een abonnement op wegens mislukte bezorging. In plaats daarvan worden nieuwe pogingen beperkt per gebeurtenis en wordt de status van het eindpunt gerapporteerd lastError (een van connection_refused, timeout, tls_error, http_4xx, http_5xx, challenge_failed) en failedSince, aanwezig terwijl het eindpunt blijft falen.

Een verbinding kan maximaal 100 actieve abonnementen bevatten. De 101ste keert terug -32013 ResourceExhausted.

events/unsubscribe​

Neemt hetzelfde name, arguments, en delivery.url, zonder geheim. Alleen de verbinding die een abonnement heeft aangemaakt, kan dit beëindigen; het verzoek van een andere referentie is een no-op. Uitschrijven is idempotent.

Fouten​

Kanera gebruikt de foutcodes van de conceptdocumenten voor evenementen. Abonnementsfouten zijn gestructureerd data zodat een host hierop kan reageren zonder berichten te parseren.

CodeerNaamWanneer
-32011NotFoundname staat niet in de catalogus (data.kind = "event").
-32012ForbiddenDe identiteit kan het aangevraagde bereik niet zien, of de referentie is geen API-sleutel of OAuth-verbinding.
-32013ResourceExhaustedDe abonnementslimiet (data.max) of een tarieflimiet.
-32014UnsupportedEen andere bezorgwijze dan webhook (data.feature, data.value).
-32015CallbackEndpointErrorVerificatie mislukt. data.reason is er één van connection_refused, timeout, tls_error, http_4xx, http_5xx, of challenge_failed. Een geweigerde bestemming wordt gerapporteerd als challenge_failed, dus foutreacties kunnen niet worden gebruikt om een particulier netwerk in kaart te brengen.
-32602InvalidParamsEen verkeerd opgemaakt verzoek, een ongeldig geheim of een ongeldige URL, een werkruimte, bord of kaart arguments dat bestaat niet, of er is geen argument aan doorgegeven priorities.changed, my_day.ready, of reminder.due.

Terugbelverificatie​

Voordat een abonnement wordt opgeslagen, bewijst Kanera dat het terugbelverzoek van jou is. Er wordt een verificatieverzoek verzonden naar delivery.url, ondertekend met het door u opgegeven geheim:

{ "type": "verification", "challenge": "…" }

Het eindpunt moet antwoorden 2xx met een JSON-body die de uitdaging precies weerspiegelt:

{ "challenge": "…" }

Met al het andere mislukt het abonneren -32015 en de reden hierboven. Omleidingen worden nooit gevolgd. Een succesvolle verificatie wordt per verbinding en callback-URL vijf minuten in de cache opgeslagen, dus verfrissend of wisselend arguments herhaalt de uitdaging niet.

Verificatie wordt uitgevoerd met hetzelfde strikte bestemmingsbeleid als levering: alleen openbare HTTPS-adressen, eenmaal opgelost en vastgezet voor de verbinding, zodat een DNS-wijziging tussen de controle en het verzoek deze niet kan omleiden.

Bezorging en nieuwe pogingen​

Elke gebeurtenis is er één POST naar het terugbelverzoek met 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
}
KoptekstInhoud
webhook-idDe eventId. Stabiel bij nieuwe pogingen; gebruik het om de handler idempotent te maken.
webhook-timestampUnix-seconden toen deze poging werd ondertekend. Vers bij elke nieuwe poging.
webhook-signatureEén of meer door spaties gescheiden v1,<base64> handtekeningen (twee tijdens een geheime rotatie).
X-MCP-Subscription-IdHet abonnement id.

De bodybytes zijn bij elke poging identiek; alleen de tijdstempel en handtekening veranderen.

Reageer 2xx erkennen. Kanera behandelt antwoorden als volgt:

ReactieGedrag
2xxGeleverd. Het lichaam wordt genegeerd.
410, 413, en andere 4xxDeze gebeurtenis wordt verwijderd. Het abonnement loopt door; toekomstige gebeurtenissen worden nog steeds afgeleverd.
408, 425, 429, 5xx, time-out, TLS of verbindingsfoutOpnieuw geprobeerd met hetzelfde eventId: vijf pogingen in totaal van ongeveer 0 s, 30 s, 1,5 min, 3,5 min en 7,5 min. Daarna wordt het voorval verwijderd.

Een antwoordtekst groter dan 4 KiB wordt weggegooid zonder de uitkomst te beïnvloeden. Een gebeurtenis groter dan 256 KiB wordt nooit verzonden. Kanera bewaart de leveringsgegevens gedurende 14 dagen.

Leveringen voor een actief abonnement overleven de herstart van Kanera. De autorisatie wordt vóór elke poging opnieuw gecontroleerd, zodat een agent waarbij de verbinding is verbroken, een ingetrokken sleutel, een verwijderd lid of een gast die een opdracht is kwijtgeraakt, bij de volgende poging geen gegevens meer ontvangt, en niet bij de volgende vernieuwing.

priorities.changed gebeurtenissen worden in de wachtrij geplaatst op het moment dat de wachtrijwijziging wordt opgeslagen, en niet vanuit het duurzame wijzigingslogboek dat door kaartgebeurtenissen wordt gebruikt, omdat de wachtrij niet aan één enkele werkruimte is gekoppeld. In het zeldzame geval dat Kanera op dat moment opnieuw opstart, kan één melding verloren gaan; de volgende priorities.list lezen is altijd actueel.

Controleer de handtekening​

Het schema is de Standaard webhooks indeling. Ontcijfer het geheim na de whsec_ voorvoegsel van base64, HMAC-SHA256 de tekenreeks {webhook-id}.{webhook-timestamp}.{body}, en vergelijk deze met elke handtekening in de header in constante tijd:

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);
});

Controleer altijd aan de hand van het ruwe lichaam. Leveringen weigeren waarvan webhook-timestamp Het duurt nog een paar minuten tot de gebonden herhaling.

Het vertellen van je eigen schrijft apart​

Een agent die op gebeurtenissen reageert door terug te schrijven, zal zijn eigen schrijfsels als gebeurtenissen zien verschijnen. userId alleen kan ze niet scheiden: een persoonlijke API-sleutel of een OAuth-agent fungeert als gebruiker, dus een opmerking die de agent heeft geplaatst en een opmerking die de persoon heeft geplaatst, hebben hetzelfde userId.

Elke gebeurtenis omvat daarom:

"actor": { "kind": "apiKey", "userId": "…", "self": true }
VeldBetekenis
kinduser (de webapp), apiKey, agent (een interactieve OAuth-agent), support, automation, of system.
userIdDe gebruiker waarvoor de wijziging is aangebracht. null voor automatisering en systeemwijzigingen.
selftrue alleen wanneer de abonnementsverbinding zelf de wijziging heeft aangebracht: dezelfde OAuth-agenttoekenning, dezelfde API-sleutel die rechtstreeks wordt gebruikt, of dezelfde onbeheerde serviceverbinding.

Automatiseringseffecten worden gerapporteerd als automation zelfs als het schrijven van de agent zelf deze triggerde, dus een regel die een label toevoegt nadat de agent commentaar heeft gegeven, wordt niet gelezen als het schrijven van de agent.

De title en text velden zijn gebruikersinhoud. Behandel ze als gegevens, nooit als instructies voor de agent.

Direct dezelfde API aanroepen​

De MCP-methoden worden doorgegeven aan drie openbare API-routes, die dezelfde dragerreferenties en dezelfde verzoek- en antwoordinstanties accepteren. Gebruik ze vanuit een integratie die een API-sleutel bevat en evenementabonnementen wil zonder MCP te spreken:

RouteMCP-methode
GET /api/v1/mcp-eventsevents/list
POST /api/v1/mcp-events/subscribeevents/subscribe
POST /api/v1/mcp-events/unsubscribeevents/unsubscribe

Fouten worden geretourneerd als openbare API-probleemdocumenten met de codes MCP_EVENT_NOT_FOUND, MCP_EVENT_UNSUPPORTED, MCP_SUBSCRIPTION_LIMIT, en MCP_CALLBACK_ENDPOINT, die de MCP-laag toewijst aan de bovenstaande foutentabel.

Voor een teamintegratie die elke verbinding moet overleven en de volledige evenementencatalogus moet bestrijken, gebruikt u Webhaken in plaats daarvan. MCP-gebeurtenisabonnementen behoren tot de inloggegevens waarmee ze zijn aangemaakt, verlopen binnen 24 uur, tenzij ze worden vernieuwd, en dekken alleen de vier kaart- en commentaargebeurtenissen plus uw eigen wachtrij 'Volgende'. Webhooks leveren geen Up next-wijzigingen op, omdat de wachtrij persoonlijk is en geen werkruimtegegevens.

Problemen oplossen​

ProbleemWat te controleren
De opdrachtgever biedt geen evenementen aan.Het moet verbinding maken met de gehoste /mcp eindpunt op het huidige MCP-protocol. Scan de server in de client opnieuw; stdio via kanera mcp biedt nooit evenementen aan.
events/subscribe retourneert -32015 met challenge_failed.De callback beantwoordde niet aan de uitdaging, beantwoordde een niet-2xx-status, werd omgeleid of bevindt zich op een privé-, loopback- of metadata-adres. Kanera rapporteert deze allemaal opzettelijk op dezelfde manier.
-32012 Forbidden op abonneren.De identiteit kan de werkruimte, het bord of de kaart niet zien. Boardgasten moeten passeren boardId; gasten met alleen toegewezen items moeten een toegewezen item doorgeven cardId. Sessiecookies kunnen zich niet abonneren; gebruik een OAuth-verbinding of een API-sleutel.
De leveringen zijn gestopt, maar het abonnement wordt nog steeds vernieuwd.Controleer deliveryStatus.lastError en failedSince op de vernieuwingsreactie. Als de referentie is ingetrokken of de gebruiker de toegang heeft verloren, is het abonnement verlopen en retourneert de vernieuwing Nee deliveryStatus.
De agent blijft reageren op zijn eigen opmerkingen.Controleer data.actor.self voordat je gaat schrijven.
-32602 bij het abonneren op priorities.changed.Passeer leeg arguments. EEN targetUserId of elk ander argument wordt afgewezen: alleen uw eigen wachtrij kan worden bekeken.
Gemiste wijzigingen na een storing.Nieuwe pogingen stoppen na ongeveer 7,5 minuten en er is geen herhaling. Lees de huidige status met cards.list, cards.get, comments.list, of priorities.list.