Reference
MCP & Events
Tool and event methods, schemas, signed webhook delivery.
All MCP JSON-RPC methods share one authenticated Streamable HTTP endpoint:
POST https://YOUR-VERCEL-HOST/mcp?key=YOUR-MCP-API-KEY
MCP_API_KEY is a shared connection credential. Do not paste its actual value in examples, issue reports, terminal history, or logs. Without a valid key, requests are rejected before reaching the MCP server.
This page covers MCP Events. Applications using normal HTTP can call the separate authenticated REST API at POST /v1/messages.
Public MCP tool
Only one tool is registered in tools/list:
send_to_dot
| Input | Type | Required | Description |
|---|---|---|---|
message |
string | Yes | The message to pass to the subscribed dot; 1–16,384 UTF-8 bytes after trimming surrounding whitespace |
Example tools/call parameters:
{
"name": "send_to_dot",
"arguments": {
"message": "Please review the deployment checklist and report any blockers."
}
}
On successful webhook delivery, the tool returns text of the form:
ChatGPT accepted event evt_<generated-id> for asynchronous processing by your dot.
This means a webhook returned HTTP 2xx. It does not mean the dot finished or even began reasoning about the message. If Redis is unavailable, there is no active subscription, input is invalid, or the callback fails, the tool returns a normal MCP tool result with isError: true and an explanatory text message.
The implementation sets the tool’s readOnlyHint client annotation as a compatibility convention. This is not a pure read: calling it transmits a message and may trigger downstream actions by a dot.
Event discovery
The same endpoint exposes protocol methods (not additional tools):
| JSON-RPC method | Function |
|---|---|
events/list |
Advertise the message.created event |
events/subscribe |
Register or refresh a single webhook subscription |
events/unsubscribe |
Remove the matching subscription |
The server advertises "events": {} in capabilities from both MCP legacy initialize and MCP 2.0 server/discover. MCP 2.0’s server/discover uses the 2026-07-28 protocol and requires the appropriate Mcp-Method header and per-request metadata for valid discovery probes. The official Go SDK owns protocol negotiation; the event capability is added by pkg/server/server.go.
events/list
The server offers one unfiltered event. The relevant result shape is:
{
"events": [
{
"name": "message.created",
"description": "A new message addressed to the single configured dot.",
"delivery": ["webhook"],
"inputSchema": {
"type": "object",
"properties": {},
"additionalProperties": false
},
"payloadSchema": {
"type": "object",
"properties": {
"message": { "type": "string" }
},
"required": ["message"],
"additionalProperties": false
}
}
],
"nextCursor": null
}
No event filters, second event type, polling mode, or stream delivery mode are supported.
events/subscribe
ChatGPT calls this method when a dot explicitly requests a subscription. Example parameters (illustrative placeholders only):
{
"name": "message.created",
"arguments": {},
"delivery": {
"mode": "webhook",
"url": "https://receiver.example.com/unique-callback",
"secret": "whsec_<base64-signing-key>"
},
"ttlMs": 3600000,
"cursor": null
}
Processing includes validation of the event name, empty arguments, HTTPS callback URL, and signing secret; a signed callback challenge must pass before the subscription becomes active. The whsec_ value must decode to a 24–64-byte key.
On success, the result includes:
{
"id": "sub_<deterministic-id>",
"refreshBefore": "2026-11-03T00:00:00Z",
"cursor": null,
"truncated": false
}
The example expiration above is illustrative, not a live server value. The actual expiration is a UTC timestamp.
- Default TTL: 7 days when
ttlMsis omitted. - Requested TTL: At least 60 seconds; capped at 7 days.
ttlMs: nullalso results in a finite 7-day subscription in this implementation. - Refresh: Calling subscribe again for the same callback updates the existing subscription, including a replacement signing secret. The result returns a new
refreshBefore. - Single subscriber: Another callback is rejected while an active different callback exists.
- Storage: Redis key
dm-dot:subscription:v1, with an expiry matching the subscription lifetime.
An idempotent subscription ID is derived from the shared authenticated principal (MCP_API_KEY), callback URL, event name, and empty event arguments. As a result, changing the MCP API key affects subscription identity; see Deployment.
events/unsubscribe
Use the same name, arguments, and delivery.mode/delivery.url that identify the subscription. The signing secret can be omitted. Removing a matching subscription returns {}; repeated unsubscription is harmless. A different callback does not clear the active subscription.
Webhook payload
send_to_dot generates one signed event object (example values):
{
"eventId": "evt_0123456789abcdef",
"name": "message.created",
"timestamp": "2026-11-03T10:30:00Z",
"data": {
"message": "Please review the deployment checklist."
},
"cursor": null
}
The event’s timestamp is set by dm-dot when it builds the event body, not when the dot begins processing it. It is an ISO 8601 UTC timestamp; the actual implementation uses nanosecond precision when available.
The server signs the exact serialized body bytes using Standard Webhooks and sends:
| Header | Meaning |
|---|---|
Content-Type: application/json |
JSON body |
webhook-id |
Matches the eventId |
webhook-timestamp |
Unix seconds at signing |
webhook-signature |
v1,<base64-HMAC-SHA256> |
X-MCP-Subscription-Id |
Subscription ID from events/subscribe |
For transient failures, the server retries up to three total attempts, preserving the event ID and serialized body. It does not store undelivered events for future retries.
Errors and edge cases
| Failure | Response |
|---|---|
Missing MCP_API_KEY environment variable |
HTTP 503 |
| Wrong or missing query-string key | HTTP 401 |
| Invalid event, filter, callback, signing secret, or TTL | JSON-RPC -32602 |
| Existing subscription for a different callback | JSON-RPC -32000 |
| Callback verification failure | JSON-RPC -32015 (CallbackEndpointError) |
| Subscription storage unavailable | JSON-RPC -32603 |
| No subscription or failed message delivery | MCP tool result with isError: true |
See Security for callback restrictions, Architecture for the life cycle, and the OpenAI MCP Events documentation for the broader event contract.