AI news

Nobody keeps a list of what is subscribed to your team's notes

By Baalda Team · · 6 min read

Short answer

The one serving them. OpenAI shipped ChatGPT support for MCP Events on 29 September 2026, so a server can push data on a standing subscription, and the draft defines no way to list live subscriptions. Whatever holds your notes has to keep that list itself: every connection, what it reached, and a revoke button.

Until last week, an AI reaching your team's notes was something that happened while you were looking at it. You asked, the agent called a tool, the tool returned, and the moment ended. MCP Events ends that. A subscription is a grant that keeps working after everyone has gone home, and the draft that defines it defines no way to list the ones you have given out.

What did OpenAI actually ship on 29 September?

At DevDay on 29 September 2026, OpenAI added ChatGPT support for the proposed MCP Events extension. OpenAI's developer documentation says ChatGPT calls three methods on your server: events/list to discover what it can watch, events/subscribe to create or refresh a subscription, and events/unsubscribe to stop. Your server advertises support by returning "events": {} in its server/discover capabilities, verifies the callback with a signed single-use challenge before it sends any application data, then POSTs each event to an HTTPS URL signed per Standard Webhooks.

The extension is not part of the MCP specification. It lives in modelcontextprotocol/experimental-ext-triggers-events, is marked Status: Draft proposal, and is dated 2026-02-19. OpenAI's page requires protocol revision 2026-07-28, supports webhook delivery only, caps a payload at 256 KiB, and lists availability as Work chats on ChatGPT web, Work chats in the desktop app with Cloud selected, and with dots.

The direction of travel is what matters. Every MCP call before this was a pull: the client asked, the server answered, nothing persisted. An event subscription is the server holding a standing instruction to send.

Why is a subscription different from a tool call?

Because a tool call is checked when it happens and a subscription is checked when it is made.

The draft is explicit that events/subscribe must run as an authenticated principal and that the subscription key is the tuple (principal, delivery.url, name, arguments). It is also explicit about the lifetime: the client suggests a ttlMs, the server returns a refreshBefore timestamp which is the actual grant, and refreshBefore: null grants no expiry at all. The client re-calls events/subscribe before that timestamp to stay alive. On revocation the design sketch says the server "SHOULD periodically re-verify permissions" without defining what periodically means.

So the thing holding open access to your data is a row in someone's database with a webhook URL on it. That is a credential, whatever it is called in the schema. WorkOS made the same observation from the identity side, and noted the design sketch states there is no server-side subscription listing method.

This is the point where it stops being a protocol question and becomes a question about where your team's knowledge lives. If the only durable record of what is still plugged into your notes is kept by the server that holds your notes, then choosing that server is the control. Baalda is a team second brain built on plain markdown files on your own disk, open source under Apache-2.0, that serves MCP at POST /api/mcp, and the part of it that answers this story is not the editor. It is the connection list.

Who can tell you what is still subscribed to your team's notes?

Only the thing serving them. ChatGPT will call events/unsubscribe when a person clicks "Stop monitoring", but OpenAI's documentation does not describe a place to see every live subscription across a workspace, and the draft gives servers no listing method to build one from. A team of ten has no identity function and no quarterly access review. The list has to come for free or it does not exist.

In Baalda it comes from the token. Every connection into a vault is a minted mcp_ token, scoped to one user and one vault, stored only as its sha256 hash so the plaintext exists exactly once, at creation. Vault Settings → MCP then shows the connections as a list, and each row carries:

  • A live dot. MCP here is stateless HTTP with no socket to watch, so "Connected" means the token made a request in the last three minutes.
  • The client's name, read off the User-Agent it sent. Claude Code, Cursor, Claude, or the leading token of whatever else connected.
  • The token prefix, so you can tell two connections apart without seeing either secret.
  • A call count, bumped per tools/call rather than per JSON-RPC message, so the number reflects work done and not handshakes.
  • Last active, as a relative time.
  • An expandable list of the 22 tools that connection can reach, each badged read, write or delete.
  • Revoke.

None of that is an audit product you buy separately. It is the same row the server reads to answer the request.

What happens when someone leaves?

The call fails, on the next call.

A Baalda MCP token encodes a user and a vault, and verifyMcpToken re-checks that user's role in that vault on every single request rather than trusting the grant that was made when the token was minted. Lose membership and the next request from that token resolves to nothing. The OAuth path does the same: consent records which vault a connector was pointed at, keyed by client and user, and the bearer is resolved through the identical membership check, so both doors land in the same place.

Compare that to the gap the MCP Events draft leaves open. A subscription granted with ttlMs: null has no refresh cycle at all, so there is no moment at which a revoked permission is noticed. Re-checking on every request is not a clever feature. It is just the only honest place to put the check when the grant outlives the conversation.

What does Baalda not do here?

It does not do MCP Events, and that is a real gap rather than a position.

Baalda's MCP server implements protocol revision 2025-06-18. It has no events/list, no events/subscribe, no events/unsubscribe, and it does not advertise an events capability. GET /api/mcp returns 405, because there is no server-to-client stream of any kind. Baalda is pull only: an agent asks, the server answers, nothing is left standing. So the actual thing OpenAI shipped on 29 September, ChatGPT reacting the moment a note changes, is not something you can do against a Baalda vault today. If that automation is what you need this quarter, a Notion or Linear MCP server that has shipped Events is the honest answer, and our Notion comparison is fairer about where Notion wins than this paragraph has room for.

Two more limits worth saying plainly. Revoking a connection stops the next read; it does not unsay what a model already read, and no access control anywhere does. And a list of connections only helps if somebody opens it. The reason to care that it is one screen rather than a log export is that one screen is the only kind of review a ten-person team actually performs.

Where does this leave a team of ten?

With one question to answer before the next connector gets added, and it is not a protocol question.

Pull-based MCP is about to stop being the only shape. The subscriptions are coming, from OpenAI first and from everyone else behind it, and they are good: an agent that notices a spec changed is worth more than one that has to be asked. What arrives with them is a class of access that persists, that nobody has to be present for, and that the current draft gives you no standard way to enumerate.

So the thing to check about whatever holds your team's written knowledge is narrow. Can you see, today, in one place, every client that can reach it, what each one is allowed to touch, when it last did, and can you cut one. If the answer is a support ticket, the answer is no. Connecting an AI to your notes over MCP is the easy half. Being able to disconnect it is the half that decides whether a team second brain is something you own or something you are renting, and it is the same reason the open source, local-first case was never really about the licence text. The setup for Baalda's own endpoint is in the MCP doc.

FAQ

Frequently asked questions

What is an MCP Events subscription, exactly?

A standing instruction you leave on someone else's server. The client calls `events/subscribe` with an event name, an HTTPS callback URL and a signing secret it generated itself. The server returns an id and a `refreshBefore` timestamp, which is the real grant, and delivers matching events to that URL signed per Standard Webhooks until the subscription expires or is ended. The client suggests a lifetime with `ttlMs`, and an explicit `ttlMs: null` requests a subscription with no expiry at all.

Is MCP Events part of the MCP specification?

Not yet. It lives in the `modelcontextprotocol/experimental-ext-triggers-events` repository, the design sketch is marked Status: Draft proposal and dated 2026-02-19, and the written text is a sketch rather than a ratified revision. OpenAI's own wording is that it is adding support for the proposed specification. Treat the field names here as liable to change.

Who can use MCP Events in ChatGPT today?

OpenAI's developer page lists it as available in Work chats on ChatGPT web, in Work chats in the desktop app with Cloud selected, and with dots. It requires protocol revision 2026-07-28, supports webhook delivery only rather than polling or streaming, and caps an event payload at 256 KiB. Coverage elsewhere has described it as available on all plans; the developer documentation is the narrower and more recent source.

Does Baalda support MCP Events?

No. Baalda's MCP server implements protocol revision 2025-06-18, advertises no events capability, and has no `events/list`, `events/subscribe` or `events/unsubscribe` handler. `GET /api/mcp` returns 405 because there is no server-to-client stream at all. Baalda is pull only: an agent asks and the server answers, with nothing left standing between calls.

How do I see which AI clients can currently reach my vault?

Open Vault Settings, then MCP. Every connection is one minted token, scoped to one person and one vault and stored only as a sha256 hash. Each row shows a live dot (a request in the last three minutes), the client's name read off its User-Agent, the token prefix, a call count bumped per `tools/call` rather than per handshake, when it was last active, the 22 tools it can reach badged read, write or delete, and a Revoke button.

What happens to an MCP token when someone leaves the team?

Its next request fails. A token encodes a user and a vault, and the server re-checks that user's role in that vault on every single request rather than trusting the grant made when the token was minted. The OAuth path resolves through the same membership check, so a connector consented to a vault dies the same way. Revoking access does not unsay what a model already read.

Start your team’s brain

Free and open source. No account needed.