Skip to main content
Glama

Cooper Email

Register webhook

cooper_register_webhook

Use this when the agent or app should be notified immediately (HTTP POST) when mail arrives instead of polling cooper_list_messages. Requires auth. Inputs: url (required; public http or https URL; localhost and private addresses are rejected), events (optional; any of message.received, message.held, message.sent, message.blocked, message.bounced, message.complained, task.received, owner.reply, domain.verified, draft.created, draft.approved, draft.rejected, draft.sent, account.sending_paused, account.sending_resumed, thread.assigned, thread.unassigned, thread.folder_updated, question.answered, question.expired; default [message.received]), inbox_id (optional; one inbox) or inbox_ids (optional; at most 10 inbox ids; omit both for every inbox), client_id (optional idempotency key; the same value returns the original hook with HTTP 200 and a redacted secret), headers (optional; up to 5 extra headers named Authorization or X-*, stored encrypted and never returned in full). Returns {id, url, events, inbox_id, inbox_ids, enabled, secret, headers (redacted), created_at}. Each delivery sends x-cooper-signature (sha256= HMAC of the raw body) and x-cooper-signature-v2 (v1= HMAC of timestamp, a dot, and the raw body) plus x-cooper-timestamp. message.blocked fires when an allow or block list drops inbound mail before it is stored. Fails with 400 too_many_inboxes, 400 invalid_url, or 404 inbox_not_found.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "url": "<url>"
    },
    "name": "cooper_register_webhook"
  }
}

Input Schema

NameRequiredDescriptionDefault
urlYesPublic https URL that receives POST deliveries
eventsNoEvent types to deliver. Default: ["message.received"]
headersNoUp to 5 extra headers sent on delivery. Names must be Authorization or X-*. Values are stored encrypted and never returned in full.
inbox_idNoOnly deliver events for this inbox. Stored into inbox_ids. Omit for every inbox on the account.
client_idNoOptional idempotency key. The same client_id returns the original hook with the secret redacted.
inbox_idsNoUp to 10 inbox ids. The hook matches when this list is empty or contains the event inbox. More than 10 returns 400 too_many_inboxes.

Output Schema

NameRequiredDescriptionDefault
idNoStable id of the returned object. Pass it to the matching get, update, or delete tool.
urlNoURL that receives POST deliveries.
eventsNoEvent types this object delivers.
secretNoSigning secret. Shown in full once on create or rotate, redacted otherwise.
enabledNoTrue when the object is active.
headersNoExtra delivery headers. Values are redacted.
inbox_idNoInbox id (inb_…) this object belongs to. Null when it applies to every inbox.
client_idNoCaller idempotency key stored with the object, or null.
inbox_idsNoInbox ids this object is limited to. Empty means every inbox on the account.
created_atNoISO-8601 time the object was created.
disabled_atNoISO-8601 time Cooper disabled the hook, or null.
disabled_reasonNoWhy the hook was disabled, or null.
consecutive_failuresNoFailed deliveries in a row.
previous_secret_activeNoTrue while deliveries are also signed with the previous secret.
previous_secret_expires_atNoISO-8601 time the previous secret stops signing, or null.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.held",
      -  "message.sent",
      -  "message.blocked",
      -  "message.bounced",
      -  "message.complained",
      -  "task.received",
      -  "owner.reply",
      -  "chat.message",
      -  "domain.verified",
      -  "draft.created",
      -  "draft.approved",
      -  "draft.rejected",
      -  "draft.sent",
      -  "account.sending_paused",
      -  "account.sending_resumed",
      -  "thread.assigned",
      -  "thread.unassigned",
      -  "thread.folder_updated",
      -  "question.answered",
      -  "question.expired",
      -  "rule.matched"
      -]New value: +[
      +  "message.received",
      +  "message.held",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "chat.message",
      +  "domain.verified",
      +  "draft.created",
      +  "draft.approved",
      +  "draft.rejected",
      +  "draft.sent",
      +  "account.sending_paused",
      +  "account.sending_resumed",
      +  "thread.assigned",
      +  "thread.unassigned",
      +  "thread.folder_updated",
      +  "question.answered",
      +  "question.expired",
      +  "rule.matched",
      +  "key.leak_reported"
      +]
  2. Changed1 schema field changed
    • changedOutput schema / (root)
      Previous value: -nullNew value: +{
      +  "additionalProperties": true,
      +  "description": "The new webhook. The secret is shown in full once.",
      +  "properties": {
      +    "client_id": {
      +      "description": "Caller idempotency key stored with the object, or null."
      +    },
      +    "consecutive_failures": {
      +      "description": "Failed deliveries in a row."
      +    },
      +    "created_at": {
      +      "description": "ISO-8601 time the object was created."
      +    },
      +    "disabled_at": {
      +      "description": "ISO-8601 time Cooper disabled the hook, or null."
      +    },
      +    "disabled_reason": {
      +      "description": "Why the hook was disabled, or null."
      +    },
      +    "enabled": {
      +      "description": "True when the object is active."
      +    },
      +    "events": {
      +      "description": "Event types this object delivers."
      +    },
      +    "headers": {
      +      "description": "Extra delivery headers. Values are redacted."
      +    },
      +    "id": {
      +      "description": "Stable id of the returned object. Pass it to the matching get, update, or delete tool."
      +    },
      +    "inbox_id": {
      +      "description": "Inbox id (inb_…) this object belongs to. Null when it applies to every inbox."
      +    },
      +    "inbox_ids": {
      +      "description": "Inbox ids this object is limited to. Empty means every inbox on the account."
      +    },
      +    "previous_secret_active": {
      +      "description": "True while deliveries are also signed with the previous secret."
      +    },
      +    "previous_secret_expires_at": {
      +      "description": "ISO-8601 time the previous secret stops signing, or null."
      +    },
      +    "secret": {
      +      "description": "Signing secret. Shown in full once on create or rotate, redacted otherwise."
      +    },
      +    "url": {
      +      "description": "URL that receives POST deliveries."
      +    }
      +  },
      +  "type": "object"
      +}
  3. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.held",
      -  "message.sent",
      -  "message.blocked",
      -  "message.bounced",
      -  "message.complained",
      -  "task.received",
      -  "owner.reply",
      -  "chat.message",
      -  "domain.verified",
      -  "draft.created",
      -  "draft.approved",
      -  "draft.rejected",
      -  "draft.sent",
      -  "account.sending_paused",
      -  "account.sending_resumed",
      -  "thread.assigned",
      -  "thread.unassigned",
      -  "thread.folder_updated",
      -  "rule.matched"
      -]New value: +[
      +  "message.received",
      +  "message.held",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "chat.message",
      +  "domain.verified",
      +  "draft.created",
      +  "draft.approved",
      +  "draft.rejected",
      +  "draft.sent",
      +  "account.sending_paused",
      +  "account.sending_resumed",
      +  "thread.assigned",
      +  "thread.unassigned",
      +  "thread.folder_updated",
      +  "question.answered",
      +  "question.expired",
      +  "rule.matched"
      +]
  4. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.held",
      -  "message.sent",
      -  "message.blocked",
      -  "message.bounced",
      -  "message.complained",
      -  "task.received",
      -  "owner.reply",
      -  "chat.message",
      -  "domain.verified",
      -  "draft.created",
      -  "draft.approved",
      -  "draft.rejected",
      -  "draft.sent",
      -  "account.sending_paused",
      -  "account.sending_resumed",
      -  "thread.assigned",
      -  "thread.unassigned",
      -  "thread.folder_updated"
      -]New value: +[
      +  "message.received",
      +  "message.held",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "chat.message",
      +  "domain.verified",
      +  "draft.created",
      +  "draft.approved",
      +  "draft.rejected",
      +  "draft.sent",
      +  "account.sending_paused",
      +  "account.sending_resumed",
      +  "thread.assigned",
      +  "thread.unassigned",
      +  "thread.folder_updated",
      +  "rule.matched"
      +]
  5. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.held",
      -  "message.sent",
      -  "message.blocked",
      -  "message.bounced",
      -  "message.complained",
      -  "task.received",
      -  "owner.reply",
      -  "chat.message",
      -  "domain.verified",
      -  "draft.created",
      -  "draft.approved",
      -  "draft.rejected",
      -  "draft.sent",
      -  "account.sending_paused",
      -  "account.sending_resumed",
      -  "thread.assigned",
      -  "thread.unassigned"
      -]New value: +[
      +  "message.received",
      +  "message.held",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "chat.message",
      +  "domain.verified",
      +  "draft.created",
      +  "draft.approved",
      +  "draft.rejected",
      +  "draft.sent",
      +  "account.sending_paused",
      +  "account.sending_resumed",
      +  "thread.assigned",
      +  "thread.unassigned",
      +  "thread.folder_updated"
      +]
  6. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.held",
      -  "message.sent",
      -  "message.blocked",
      -  "message.bounced",
      -  "message.complained",
      -  "task.received",
      -  "owner.reply",
      -  "domain.verified",
      -  "draft.created",
      -  "draft.approved",
      -  "draft.rejected",
      -  "draft.sent",
      -  "account.sending_paused",
      -  "account.sending_resumed",
      -  "thread.assigned",
      -  "thread.unassigned"
      -]New value: +[
      +  "message.received",
      +  "message.held",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "chat.message",
      +  "domain.verified",
      +  "draft.created",
      +  "draft.approved",
      +  "draft.rejected",
      +  "draft.sent",
      +  "account.sending_paused",
      +  "account.sending_resumed",
      +  "thread.assigned",
      +  "thread.unassigned"
      +]
  7. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.held",
      -  "message.sent",
      -  "message.blocked",
      -  "message.bounced",
      -  "message.complained",
      -  "task.received",
      -  "owner.reply",
      -  "domain.verified",
      -  "draft.created",
      -  "draft.approved",
      -  "draft.rejected",
      -  "draft.sent"
      -]New value: +[
      +  "message.received",
      +  "message.held",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "domain.verified",
      +  "draft.created",
      +  "draft.approved",
      +  "draft.rejected",
      +  "draft.sent",
      +  "account.sending_paused",
      +  "account.sending_resumed",
      +  "thread.assigned",
      +  "thread.unassigned"
      +]
  8. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.held",
      -  "message.sent",
      -  "message.blocked",
      -  "message.bounced",
      -  "message.complained",
      -  "task.received",
      -  "owner.reply",
      -  "domain.verified"
      -]New value: +[
      +  "message.received",
      +  "message.held",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "domain.verified",
      +  "draft.created",
      +  "draft.approved",
      +  "draft.rejected",
      +  "draft.sent"
      +]
  9. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.sent",
      -  "message.blocked",
      -  "message.bounced",
      -  "message.complained",
      -  "task.received",
      -  "owner.reply",
      -  "domain.verified"
      -]New value: +[
      +  "message.received",
      +  "message.held",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "domain.verified"
      +]
  10. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.sent",
      -  "message.blocked",
      -  "task.received",
      -  "owner.reply",
      -  "domain.verified"
      -]New value: +[
      +  "message.received",
      +  "message.sent",
      +  "message.blocked",
      +  "message.bounced",
      +  "message.complained",
      +  "task.received",
      +  "owner.reply",
      +  "domain.verified"
      +]
  11. Changed4 schema fields changed
    • addedInput schema / properties / client_id
      Added value: +{
      +  "description": "Optional idempotency key. The same client_id returns the original hook with the secret redacted.",
      +  "type": "string"
      +}
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.sent",
      -  "message.blocked",
      -  "task.received",
      -  "owner.reply"
      -]New value: +[
      +  "message.received",
      +  "message.sent",
      +  "message.blocked",
      +  "task.received",
      +  "owner.reply",
      +  "domain.verified"
      +]
    • changedInput schema / properties / inbox_id / description
      Previous value: -"Only deliver events for this inbox. Omit for every inbox on the account."New value: +"Only deliver events for this inbox. Stored into inbox_ids. Omit for every inbox on the account."
    • addedInput schema / properties / inbox_ids
      Added value: +{
      +  "description": "Up to 10 inbox ids. The hook matches when this list is empty or contains the event inbox. More than 10 returns 400 too_many_inboxes.",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
  12. Changed1 schema field changed
    • changedInput schema / properties / events / items / enum
      Previous value: -[
      -  "message.received",
      -  "message.sent",
      -  "task.received",
      -  "owner.reply"
      -]New value: +[
      +  "message.received",
      +  "message.sent",
      +  "message.blocked",
      +  "task.received",
      +  "owner.reply"
      +]
  13. Changed2 schema fields changed
    • addedInput schema / properties / events / description
      Added value: +"Event types to deliver. Default: [\"message.received\"]"
    • addedInput schema / properties / url / description
      Added value: +"Public https URL that receives POST deliveries"
  14. Changed2 schema fields changed
    • addedInput schema / properties / headers
      Added value: +{
      +  "additionalProperties": {
      +    "type": "string"
      +  },
      +  "description": "Up to 5 extra headers sent on delivery. Names must be Authorization or X-*. Values are stored encrypted and never returned in full.",
      +  "type": "object"
      +}
    • addedInput schema / properties / inbox_id
      Added value: +{
      +  "description": "Only deliver events for this inbox. Omit for every inbox on the account.",
      +  "type": "string"
      +}
  15. First observed

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the annotations: requires auth, discloses the delivery signature scheme (x-cooper-signature sha256 HMAC and v2 timestamp-dot-body variant), states that header values are stored encrypted and never returned in full, that secrets are redacted on idempotent replay, and enumerates concrete error codes (400 too_many_inboxes, 400 invalid_url, 404 inbox_not_found). Also explains the non-obvious semantics of message.blocked (fires before storage).

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the use case, which is good, but it is a single dense run-on paragraph whose longest section is a 20-item event enumeration that is already in the schema and is incomplete relative to it. That block does not earn its space and buries the genuinely useful details (signature scheme, redaction, error codes).

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 6-parameter mutation tool with an output schema, the description covers auth, side effects, delivery contract, and failure modes, so an agent has nearly everything needed. The remaining defect is accuracy rather than coverage: the http-vs-https and events-list mismatches with the schema leave room for wrong assumptions.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Adds genuine meaning over a 100%-covered schema: localhost/private addresses rejected for url, inbox_id vs inbox_ids mutual exclusivity and the 10-inbox cap, and client_id replay semantics. However it restates the events list, which duplicates the schema enum and drifts from it (the description omits chat.message, rule.matched, and key.leak_reported that the schema allows), and it says 'http or https' while the schema says 'Public https URL' — an agent could resolve that inconsistently.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (register a webhook) and immediately frames the intent: get HTTP POST notifications on mail arrival instead of polling cooper_list_messages. An agent can distinguish this from cooper_list_webhooks, cooper_update_webhook, cooper_test_webhook, and cooper_poll_events without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly names the alternative it replaces (polling cooper_list_messages) and the condition that selects it (agent/app should be notified immediately). No when-not-to-use clause, but the alternative routing is unambiguous.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.