Push Notifications

infrastrActure can push config-change events to registered clients instead of waiting for clients to poll. This is handled by services/webhookEmitter.ts.

How It Fits

The notification is fire-and-forget — it never blocks the primary operation and never surfaces errors to the caller.

Configuration

Set these env vars on the infrastrActure instance:

VariableRequiredNotes
WEBHOOK_CLIENT_URLyesFull URL to the client receiver endpoint
WEBHOOK_CLIENT_SECRETyesShared secret, sent as Authorization: Bearer <secret>

If neither URL variable is set, the emitter is silently disabled and clients fall back to polling.

Payload

{
  "event": "installation_created",
  "instanceId": "my-instance-id",
  "delta": {
    "added": {
      "github-mcp__user_42__install_abc": {
        "type": "streamable",
        "url": "http://host:port/mcp"
      }
    },
    "removed": []
  },
  "meta": {
    "userId": "42",
    "toolId": "github-mcp"
  }
}
FieldDescription
eventWhat changed — see event types below
instanceIdTarget instance; receivers should ignore events for other instances
delta.addedMap of server name → full MCP server config object
delta.removedList of server names to drop from local config
metaOptional context (userId, toolId, etc.)

Event Types

EventTrigger
installation_createdUser installs a tool
installation_deletedUser removes a tool
installation_updatedInstallation config changes
shared_tool_startedShared tool container comes up
shared_tool_stoppedShared tool container goes down
sandbox_startedSandbox runtime starts
sandbox_stoppedSandbox runtime stops
sandbox_destroyedSandbox is deleted
config_changedGeneric — full re-sync needed (no delta available)

Receiver Contract

Any client can consume these events. The receiver must:

  1. Accept POST on the configured URL
  2. Validate Authorization: Bearer <secret>
  3. Optionally check instanceId — ignore events for other instances
  4. Respond 200 immediately
  5. Apply the delta or trigger a re-sync asynchronously

delta is preferred over config_changed when the caller knows exactly which servers changed. Clients that support delta application can update their config without a round-trip to the integration endpoint.

Minimal Receiver (Express)

app.post("/mcp/webhook/config-changed", async (req, res) => {
  const token = (req.headers.authorization || "").replace("Bearer ", "");
  if (token !== process.env.WEBHOOK_CLIENT_SECRET) {
    return res.status(401).json({ error: "Unauthorized" });
  }

  res.status(200).json({ ok: true }); // acknowledge before any async work

  const { delta } = req.body;
  if (delta?.added || delta?.removed) {
    await hypervisor.applySyncDelta(delta);
  } else {
    await hypervisor.syncFromInfrastrActure(/* ... */);
  }
});

Relation to Polling

Push notifications are the primary sync path. Clients should still run a periodic fallback poll (15-minute interval recommended) to catch any missed events caused by network blips or service restarts.

Client-Side Reload Safety

The point of sending a delta is to let clients reload their MCP connections without interrupting active tool calls. This section explains what a safe reload looks like so you can implement it correctly in your own stack — language and framework are up to you.

The problem with a naïve reload

If you disconnect all MCP servers and reconnect from scratch, any tool call that is mid-flight at that moment will fail. In a multi-user system that may be someone else's request entirely.

What safe reload looks like

A safe reload follows this sequence:

Key properties:

  • Build first, swap second. The old client stays alive while the new one connects. If the new client fails to connect any server, the old one is still serving requests.
  • Atomic cache swap. All internal references (client, tool map, toolset map) are replaced in one synchronous step. There is no moment where a caller can observe a partial state.
  • Tool references are self-contained. Tool objects returned to callers close over their own server connection, not the parent client. An in-flight call holding a reference to an old tool object will still complete after the client reference has been replaced — as long as the underlying connection hasn't been closed yet.
  • Grace period before disconnect. Wait long enough for in-flight calls to finish before closing old connections. 10 seconds covers the overwhelming majority of MCP tool calls (calendar reads, searches, filesystem ops). If your stack has longer-running tools, increase it or track active call counts and drain to zero before disconnecting.

What your receiver needs to do

  1. Acknowledge the webhook 200 OK before starting the reload. Never block the response on reconnection work.
  2. Apply the delta to your local config store.
  3. Build a new client against the updated config.
  4. Atomically swap your shared client/tool references.
  5. Schedule disconnection of the old client after your grace period.