shipmail-mcp 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Shipmail",
3
3
  "name": "shipmail",
4
- "version": "0.9.1",
4
+ "version": "0.9.3",
5
5
  "description": "Modern email for your business. Inboxes, calendars, newsletters, bookings, an AI assistant, and an API for your agents. Everything on your own domain, in one subscription.",
6
6
  "author": {
7
7
  "name": "Shipmail",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipmail",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Modern email for your business. Inboxes, calendars, newsletters, bookings, an AI assistant, and an API for your agents. Everything on your own domain, in one subscription.",
5
5
  "author": {
6
6
  "name": "Shipmail",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipmail",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Modern email for your business. Inboxes, calendars, newsletters, bookings, an AI assistant, and an API for your agents. Everything on your own domain, in one subscription.",
5
5
  "author": {
6
6
  "name": "Shipmail",
@@ -143,7 +143,7 @@ declare const MCP_PERMISSION_GROUPS: readonly [{
143
143
  readonly scopes: readonly ["suppressions:read", "suppressions:write"];
144
144
  readonly persistent: false;
145
145
  }];
146
- declare const CAPABILITY_ROWS: readonly [readonly ["shipmail_status", "getStatus", "public"], readonly ["shipmail_list_automations", "listAutomations", "automations:read"], readonly ["shipmail_create_automation", "createAutomation", "automations:write"], readonly ["shipmail_get_automation", "getAutomation", "automations:read"], readonly ["shipmail_update_automation", "updateAutomation", "automations:write"], readonly ["shipmail_run_automation", "runAutomation", "automations:write"], readonly ["shipmail_create_domain", "createDomain", "domains:write"], readonly ["shipmail_list_domains", "listDomains", "domains:read"], readonly ["shipmail_get_domain", "getDomain", "domains:read"], readonly ["shipmail_get_domain_dns_records", "getDomainDnsRecords", "domains:read"], readonly ["shipmail_update_domain", "updateDomain", "domains:write"], readonly ["shipmail_delete_domain", "deleteDomain", "domains:write"], readonly ["shipmail_verify_domain", "verifyDomain", "domains:write"], readonly ["shipmail_search_domains", "searchDomains", "domains:read"], readonly ["shipmail_create_mailbox", "createMailbox", "mailboxes:write"], readonly ["shipmail_list_mailboxes", "listMailboxes", "mailboxes:read"], readonly ["shipmail_get_mailbox", "getMailbox", "mailboxes:read"], readonly ["shipmail_list_mailbox_app_passwords", "listMailboxAppPasswords", "mailbox_credentials:read"], readonly ["shipmail_create_mailbox_app_password", "createMailboxAppPassword", "mailbox_credentials:write"], readonly ["shipmail_revoke_mailbox_app_password", "revokeMailboxAppPassword", "mailbox_credentials:write"], readonly ["shipmail_suspend_mailbox", "suspendMailbox", "mailboxes:write"], readonly ["shipmail_resume_mailbox", "resumeMailbox", "mailboxes:write"], readonly ["shipmail_create_mailbox_export", "createMailboxExport", "mailboxes:export"], readonly ["shipmail_get_mailbox_export", "getMailboxExport", "mailboxes:export"], readonly ["shipmail_update_mailbox", "updateMailbox", "mailboxes:write"], readonly ["shipmail_delete_mailbox", "deleteMailbox", "mailboxes:write"], readonly ["shipmail_list_mailbox_folders", "listMailboxFolders", "mailboxes:read"], readonly ["shipmail_create_mailbox_folder", "createMailboxFolder", "messages:write"], readonly ["shipmail_update_mailbox_folder", "updateMailboxFolder", "messages:write"], readonly ["shipmail_delete_mailbox_folder", "deleteMailboxFolder", "messages:write"], readonly ["shipmail_list_mailbox_rules", "getMailboxRules", "mailbox_rules:read"], readonly ["shipmail_get_mailbox_rule", "getMailboxRules", "mailbox_rules:read"], readonly ["shipmail_create_mailbox_rule", "updateMailboxRules", "mailbox_rules:write"], readonly ["shipmail_update_mailbox_rule", "updateMailboxRules", "mailbox_rules:write"], readonly ["shipmail_delete_mailbox_rule", "updateMailboxRules", "mailbox_rules:write"], readonly ["shipmail_list_mailbox_identities", "listMailboxIdentities", "mailboxes:read"], readonly ["shipmail_list_mailbox_inbox_messages", "listMailboxInboxMessages", "messages:read"], readonly ["shipmail_get_mailbox_inbox_message", "getMailboxInboxMessage", "messages:read"], readonly ["shipmail_read_mailbox_inbox_attachment", "downloadMailboxInboxAttachment", "messages:read"], readonly ["shipmail_list_mailbox_inbox_threads", "listMailboxInboxThreads", "messages:read"], readonly ["shipmail_get_mailbox_inbox_thread", "getMailboxInboxThread", "messages:read"], readonly ["shipmail_update_inbox_thread_attention", "updateMailboxInboxThreadAttention", "messages:write"], readonly ["shipmail_create_draft", "createMailboxInboxDraft", "drafts:compose"], readonly ["shipmail_create_inbox_reply_draft", "createMailboxInboxReplyDraft", "drafts:write"], readonly ["shipmail_send_inbox_reply_draft", "sendMailboxInboxReplyDraft", "messages:send"], readonly ["shipmail_reply_to_inbox_message", "replyToMailboxInboxMessage", "messages:send"], readonly ["shipmail_reply_to_inbox_thread", "replyToMailboxInboxThread", "messages:send"], readonly ["shipmail_update_inbox_message", "updateMailboxInboxMessage", "messages:write"], readonly ["shipmail_move_inbox_message", "moveMailboxInboxMessage", "messages:write"], readonly ["shipmail_delete_inbox_message", "deleteMailboxInboxMessage", "messages:write"], readonly ["shipmail_list_mailbox_forwarding", "listMailboxForwarding", "mailbox_forwarding:read"], readonly ["shipmail_create_mailbox_forwarding", "createMailboxForwarding", "mailbox_forwarding:write"], readonly ["shipmail_delete_mailbox_forwarding", "deleteMailboxForwarding", "mailbox_forwarding:write"], readonly ["shipmail_reset_mailbox_password", "resetMailboxPassword", "mailboxes:write"], readonly ["shipmail_set_auto_reply", "updateAutoReply", "mailboxes:write"], readonly ["shipmail_get_mailbox_delivery_routing", "getMailboxDeliveryRouting", "mailboxes:read"], readonly ["shipmail_update_mailbox_delivery_routing", "updateMailboxDeliveryRouting", "mailboxes:write"], readonly ["shipmail_create_mailbox_import", "createMailboxImport", "mailboxes:write"], readonly ["shipmail_list_mailbox_imports", "listMailboxImports", "mailboxes:read"], readonly ["shipmail_get_mailbox_import", "getMailboxImport", "mailboxes:read"], readonly ["shipmail_cancel_mailbox_import", "cancelMailboxImport", "mailboxes:write"], readonly ["shipmail_resume_mailbox_import", "resumeMailboxImport", "mailboxes:write"], readonly ["shipmail_restore_mailbox_import", "restoreMailboxImport", "mailboxes:write"], readonly ["shipmail_undo_mailbox_import", "undoMailboxImport", "mailboxes:write"], readonly ["shipmail_inject_sandbox_inbound", "injectSandboxInbound", "messages:write"], readonly ["shipmail_list_messages", "listMessages", "messages:read"], readonly ["shipmail_list_message_analytics", "listMessageAnalytics", "messages:read"], readonly ["shipmail_compose_message_with_file", "prepareStagedAttachmentUpload", "messages:send"], readonly ["shipmail_prepare_staged_attachment_upload", "prepareStagedAttachmentUpload", "messages:send"], readonly ["shipmail_send_message", "sendMessage", "messages:send"], readonly ["shipmail_list_scheduled_messages", "listScheduledMessages", "messages:read"], readonly ["shipmail_get_scheduled_message", "getScheduledMessage", "messages:read"], readonly ["shipmail_update_scheduled_message", "updateScheduledMessage", "messages:send"], readonly ["shipmail_cancel_scheduled_message", "cancelScheduledMessage", "messages:send"], readonly ["shipmail_get_message", "getMessage", "messages:read"], readonly ["shipmail_reply_to_message", "replyToMessage", "messages:send"], readonly ["shipmail_list_threads", "listThreads", "threads:read"], readonly ["shipmail_get_thread", "getThread", "threads:read"], readonly ["shipmail_reply_to_thread", "replyToThread", "messages:send"], readonly ["shipmail_create_reply_scan", "createReplyScan", "messages:write"], readonly ["shipmail_get_reply_scan", "getReplyScan", "messages:read"], readonly ["shipmail_list_reply_scan_results", "listReplyScanResults", "messages:read"], readonly ["shipmail_list_members", "listMembers", "members:read"], readonly ["shipmail_get_member", "getMember", "members:read"], readonly ["shipmail_create_webhook", "createWebhook", "webhooks:write"], readonly ["shipmail_list_webhooks", "listWebhooks", "webhooks:read"], readonly ["shipmail_get_webhook", "getWebhook", "webhooks:read"], readonly ["shipmail_update_webhook", "updateWebhook", "webhooks:write"], readonly ["shipmail_delete_webhook", "deleteWebhook", "webhooks:write"], readonly ["shipmail_rotate_webhook_secret", "rotateWebhookSecret", "webhooks:write"], readonly ["shipmail_test_webhook", "testWebhook", "webhooks:write"], readonly ["shipmail_list_webhook_deliveries", "listWebhookDeliveries", "webhooks:read"], readonly ["shipmail_get_webhook_delivery", "getWebhookDelivery", "webhooks:read"], readonly ["shipmail_replay_webhook_delivery", "replayWebhookDelivery", "webhooks:write"], readonly ["shipmail_list_suppressions", "listSuppressions", "suppressions:read"], readonly ["shipmail_remove_suppression", "removeSuppression", "suppressions:write"], readonly ["shipmail_create_audience", "createAudience", "audiences:write"], readonly ["shipmail_list_audiences", "listAudiences", "audiences:read"], readonly ["shipmail_get_audience", "getAudience", "audiences:read"], readonly ["shipmail_update_audience", "updateAudience", "audiences:write"], readonly ["shipmail_delete_audience", "deleteAudience", "audiences:write"], readonly ["shipmail_get_audience_feed", "getAudienceFeed", "audiences:read"], readonly ["shipmail_update_audience_feed", "updateAudienceFeed", "audiences:write"], readonly ["shipmail_rotate_audience_feed", "rotateAudienceFeedToken", "audiences:write"], readonly ["shipmail_revoke_audience_feed", "revokeAudienceFeedToken", "audiences:write"], readonly ["shipmail_add_subscriber", "addSubscriber", "audiences:write"], readonly ["shipmail_add_subscribers_batch", "addSubscribersBatch", "audiences:write"], readonly ["shipmail_list_subscribers", "listSubscribers", "audiences:read"], readonly ["shipmail_get_subscriber", "getSubscriber", "audiences:read"], readonly ["shipmail_get_subscriber_by_email", "getSubscriberByEmail", "audiences:read"], readonly ["shipmail_update_subscriber", "updateSubscriber", "audiences:write"], readonly ["shipmail_unsubscribe_subscriber", "unsubscribeSubscriber", "audiences:write"], readonly ["shipmail_resubscribe_subscriber", "resubscribeSubscriber", "audiences:write"], readonly ["shipmail_remove_subscriber", "removeSubscriber", "audiences:write"], readonly ["shipmail_list_newsletter_domains", "listNewsletterDomains", "newsletters:read"], readonly ["shipmail_list_newsletter_sender_identities", "listNewsletterSenderIdentities", "newsletters:read"], readonly ["shipmail_create_newsletter", "createNewsletter", "newsletters:write"], readonly ["shipmail_create_newsletter_from_changelog", "createNewsletterFromChangelog", "newsletters:write"], readonly ["shipmail_list_newsletters", "listNewsletters", "newsletters:read"], readonly ["shipmail_get_newsletter", "getNewsletter", "newsletters:read"], readonly ["shipmail_update_newsletter", "updateNewsletter", "newsletters:write"], readonly ["shipmail_list_newsletter_assets", "listNewsletterAssets", "newsletters:read"], readonly ["shipmail_upload_newsletter_asset_with_file", "prepareNewsletterAssetUpload", "newsletters:write"], readonly ["shipmail_prepare_newsletter_asset_upload", "prepareNewsletterAssetUpload", "newsletters:write"], readonly ["shipmail_register_newsletter_asset", "uploadNewsletterAsset", "newsletters:write"], readonly ["shipmail_preview_newsletter", "previewNewsletter", "newsletters:read"], readonly ["shipmail_run_newsletter_preflight", "runNewsletterPreflight", "newsletters:write"], readonly ["shipmail_send_newsletter_test", "sendNewsletterTest", "newsletters:write"], readonly ["shipmail_schedule_newsletter", "scheduleNewsletter", "newsletters:write"], readonly ["shipmail_cancel_newsletter", "cancelNewsletter", "newsletters:write"], readonly ["shipmail_resume_newsletter", "resumeNewsletter", "newsletters:write"], readonly ["shipmail_list_calendar_events", "listCalendarEvents", "calendar:read"], readonly ["shipmail_create_calendar_event", "createCalendarEvent", "calendar:write"], readonly ["shipmail_get_calendar_event", "getCalendarEvent", "calendar:read"], readonly ["shipmail_update_calendar_event", "updateCalendarEvent", "calendar:write"], readonly ["shipmail_delete_calendar_event", "deleteCalendarEvent", "calendar:write"], readonly ["shipmail_get_calendar_availability", "getCalendarAvailability", "calendar:read"], readonly ["shipmail_list_booking_pages", "listBookingPages", "booking_pages:read"], readonly ["shipmail_create_booking_page", "createBookingPage", "booking_pages:write"], readonly ["shipmail_get_booking_page", "getBookingPage", "booking_pages:read"], readonly ["shipmail_update_booking_page", "updateBookingPage", "booking_pages:write"], readonly ["shipmail_delete_booking_page", "deleteBookingPage", "booking_pages:write"]];
146
+ declare const CAPABILITY_ROWS: readonly [readonly ["shipmail_status", "getStatus", "public"], readonly ["shipmail_get_organization_access", "getOrganizationAccess", "public"], readonly ["shipmail_list_automations", "listAutomations", "automations:read"], readonly ["shipmail_create_automation", "createAutomation", "automations:write"], readonly ["shipmail_get_automation", "getAutomation", "automations:read"], readonly ["shipmail_update_automation", "updateAutomation", "automations:write"], readonly ["shipmail_run_automation", "runAutomation", "automations:write"], readonly ["shipmail_create_domain", "createDomain", "domains:write"], readonly ["shipmail_list_domains", "listDomains", "domains:read"], readonly ["shipmail_get_domain", "getDomain", "domains:read"], readonly ["shipmail_get_domain_dns_records", "getDomainDnsRecords", "domains:read"], readonly ["shipmail_update_domain", "updateDomain", "domains:write"], readonly ["shipmail_delete_domain", "deleteDomain", "domains:write"], readonly ["shipmail_verify_domain", "verifyDomain", "domains:write"], readonly ["shipmail_search_domains", "searchDomains", "domains:read"], readonly ["shipmail_create_mailbox", "createMailbox", "mailboxes:write"], readonly ["shipmail_list_mailboxes", "listMailboxes", "mailboxes:read"], readonly ["shipmail_get_mailbox", "getMailbox", "mailboxes:read"], readonly ["shipmail_list_mailbox_app_passwords", "listMailboxAppPasswords", "mailbox_credentials:read"], readonly ["shipmail_create_mailbox_app_password", "createMailboxAppPassword", "mailbox_credentials:write"], readonly ["shipmail_revoke_mailbox_app_password", "revokeMailboxAppPassword", "mailbox_credentials:write"], readonly ["shipmail_suspend_mailbox", "suspendMailbox", "mailboxes:write"], readonly ["shipmail_resume_mailbox", "resumeMailbox", "mailboxes:write"], readonly ["shipmail_create_mailbox_export", "createMailboxExport", "mailboxes:export"], readonly ["shipmail_get_mailbox_export", "getMailboxExport", "mailboxes:export"], readonly ["shipmail_update_mailbox", "updateMailbox", "mailboxes:write"], readonly ["shipmail_delete_mailbox", "deleteMailbox", "mailboxes:write"], readonly ["shipmail_list_mailbox_folders", "listMailboxFolders", "mailboxes:read"], readonly ["shipmail_create_mailbox_folder", "createMailboxFolder", "messages:write"], readonly ["shipmail_update_mailbox_folder", "updateMailboxFolder", "messages:write"], readonly ["shipmail_delete_mailbox_folder", "deleteMailboxFolder", "messages:write"], readonly ["shipmail_list_mailbox_rules", "getMailboxRules", "mailbox_rules:read"], readonly ["shipmail_get_mailbox_rule", "getMailboxRules", "mailbox_rules:read"], readonly ["shipmail_create_mailbox_rule", "updateMailboxRules", "mailbox_rules:write"], readonly ["shipmail_update_mailbox_rule", "updateMailboxRules", "mailbox_rules:write"], readonly ["shipmail_delete_mailbox_rule", "updateMailboxRules", "mailbox_rules:write"], readonly ["shipmail_list_mailbox_identities", "listMailboxIdentities", "mailboxes:read"], readonly ["shipmail_list_mailbox_inbox_messages", "listMailboxInboxMessages", "messages:read"], readonly ["shipmail_get_mailbox_inbox_message", "getMailboxInboxMessage", "messages:read"], readonly ["shipmail_read_mailbox_inbox_attachment", "downloadMailboxInboxAttachment", "messages:read"], readonly ["shipmail_list_mailbox_inbox_threads", "listMailboxInboxThreads", "messages:read"], readonly ["shipmail_get_mailbox_inbox_thread", "getMailboxInboxThread", "messages:read"], readonly ["shipmail_update_inbox_thread_attention", "updateMailboxInboxThreadAttention", "messages:write"], readonly ["shipmail_create_draft", "createMailboxInboxDraft", "drafts:compose"], readonly ["shipmail_create_inbox_reply_draft", "createMailboxInboxReplyDraft", "drafts:write"], readonly ["shipmail_send_inbox_reply_draft", "sendMailboxInboxReplyDraft", "messages:send"], readonly ["shipmail_reply_to_inbox_message", "replyToMailboxInboxMessage", "messages:send"], readonly ["shipmail_reply_to_inbox_thread", "replyToMailboxInboxThread", "messages:send"], readonly ["shipmail_update_inbox_message", "updateMailboxInboxMessage", "messages:write"], readonly ["shipmail_move_inbox_message", "moveMailboxInboxMessage", "messages:write"], readonly ["shipmail_delete_inbox_message", "deleteMailboxInboxMessage", "messages:write"], readonly ["shipmail_list_mailbox_forwarding", "listMailboxForwarding", "mailbox_forwarding:read"], readonly ["shipmail_create_mailbox_forwarding", "createMailboxForwarding", "mailbox_forwarding:write"], readonly ["shipmail_delete_mailbox_forwarding", "deleteMailboxForwarding", "mailbox_forwarding:write"], readonly ["shipmail_reset_mailbox_password", "resetMailboxPassword", "mailbox_credentials:write"], readonly ["shipmail_set_auto_reply", "updateAutoReply", "mailboxes:write"], readonly ["shipmail_get_mailbox_delivery_routing", "getMailboxDeliveryRouting", "mailboxes:read"], readonly ["shipmail_update_mailbox_delivery_routing", "updateMailboxDeliveryRouting", "mailboxes:write"], readonly ["shipmail_create_mailbox_import", "createMailboxImport", "mailboxes:write"], readonly ["shipmail_list_mailbox_imports", "listMailboxImports", "mailboxes:read"], readonly ["shipmail_get_mailbox_import", "getMailboxImport", "mailboxes:read"], readonly ["shipmail_cancel_mailbox_import", "cancelMailboxImport", "mailboxes:write"], readonly ["shipmail_resume_mailbox_import", "resumeMailboxImport", "mailboxes:write"], readonly ["shipmail_restore_mailbox_import", "restoreMailboxImport", "mailboxes:write"], readonly ["shipmail_undo_mailbox_import", "undoMailboxImport", "mailboxes:write"], readonly ["shipmail_inject_sandbox_inbound", "injectSandboxInbound", "messages:write"], readonly ["shipmail_list_messages", "listMessages", "messages:read"], readonly ["shipmail_list_message_analytics", "listMessageAnalytics", "messages:read"], readonly ["shipmail_compose_message_with_file", "prepareStagedAttachmentUpload", "messages:send"], readonly ["shipmail_prepare_staged_attachment_upload", "prepareStagedAttachmentUpload", "messages:send"], readonly ["shipmail_send_message", "sendMessage", "messages:send"], readonly ["shipmail_list_scheduled_messages", "listScheduledMessages", "messages:read"], readonly ["shipmail_get_scheduled_message", "getScheduledMessage", "messages:read"], readonly ["shipmail_update_scheduled_message", "updateScheduledMessage", "messages:send"], readonly ["shipmail_cancel_scheduled_message", "cancelScheduledMessage", "messages:send"], readonly ["shipmail_get_message", "getMessage", "messages:read"], readonly ["shipmail_reply_to_message", "replyToMessage", "messages:send"], readonly ["shipmail_list_threads", "listThreads", "threads:read"], readonly ["shipmail_get_thread", "getThread", "threads:read"], readonly ["shipmail_reply_to_thread", "replyToThread", "messages:send"], readonly ["shipmail_create_reply_scan", "createReplyScan", "messages:write"], readonly ["shipmail_get_reply_scan", "getReplyScan", "messages:read"], readonly ["shipmail_list_reply_scan_results", "listReplyScanResults", "messages:read"], readonly ["shipmail_list_members", "listMembers", "members:read"], readonly ["shipmail_get_member", "getMember", "members:read"], readonly ["shipmail_create_webhook", "createWebhook", "webhooks:write"], readonly ["shipmail_list_webhooks", "listWebhooks", "webhooks:read"], readonly ["shipmail_get_webhook", "getWebhook", "webhooks:read"], readonly ["shipmail_update_webhook", "updateWebhook", "webhooks:write"], readonly ["shipmail_delete_webhook", "deleteWebhook", "webhooks:write"], readonly ["shipmail_rotate_webhook_secret", "rotateWebhookSecret", "webhooks:write"], readonly ["shipmail_test_webhook", "testWebhook", "webhooks:write"], readonly ["shipmail_list_webhook_deliveries", "listWebhookDeliveries", "webhooks:read"], readonly ["shipmail_get_webhook_delivery", "getWebhookDelivery", "webhooks:read"], readonly ["shipmail_replay_webhook_delivery", "replayWebhookDelivery", "webhooks:write"], readonly ["shipmail_list_suppressions", "listSuppressions", "suppressions:read"], readonly ["shipmail_remove_suppression", "removeSuppression", "suppressions:write"], readonly ["shipmail_create_audience", "createAudience", "audiences:write"], readonly ["shipmail_list_audiences", "listAudiences", "audiences:read"], readonly ["shipmail_get_audience", "getAudience", "audiences:read"], readonly ["shipmail_update_audience", "updateAudience", "audiences:write"], readonly ["shipmail_delete_audience", "deleteAudience", "audiences:write"], readonly ["shipmail_get_audience_feed", "getAudienceFeed", "audiences:read"], readonly ["shipmail_update_audience_feed", "updateAudienceFeed", "audiences:write"], readonly ["shipmail_rotate_audience_feed", "rotateAudienceFeedToken", "audiences:write"], readonly ["shipmail_revoke_audience_feed", "revokeAudienceFeedToken", "audiences:write"], readonly ["shipmail_add_subscriber", "addSubscriber", "audiences:write"], readonly ["shipmail_add_subscribers_batch", "addSubscribersBatch", "audiences:write"], readonly ["shipmail_list_subscribers", "listSubscribers", "audiences:read"], readonly ["shipmail_get_subscriber", "getSubscriber", "audiences:read"], readonly ["shipmail_get_subscriber_by_email", "getSubscriberByEmail", "audiences:read"], readonly ["shipmail_update_subscriber", "updateSubscriber", "audiences:write"], readonly ["shipmail_unsubscribe_subscriber", "unsubscribeSubscriber", "audiences:write"], readonly ["shipmail_resubscribe_subscriber", "resubscribeSubscriber", "audiences:write"], readonly ["shipmail_remove_subscriber", "removeSubscriber", "audiences:write"], readonly ["shipmail_list_newsletter_domains", "listNewsletterDomains", "newsletters:read"], readonly ["shipmail_list_newsletter_sender_identities", "listNewsletterSenderIdentities", "newsletters:read"], readonly ["shipmail_create_newsletter", "createNewsletter", "newsletters:write"], readonly ["shipmail_create_newsletter_from_changelog", "createNewsletterFromChangelog", "newsletters:write"], readonly ["shipmail_list_newsletters", "listNewsletters", "newsletters:read"], readonly ["shipmail_get_newsletter", "getNewsletter", "newsletters:read"], readonly ["shipmail_update_newsletter", "updateNewsletter", "newsletters:write"], readonly ["shipmail_list_newsletter_assets", "listNewsletterAssets", "newsletters:read"], readonly ["shipmail_upload_newsletter_asset_with_file", "prepareNewsletterAssetUpload", "newsletters:write"], readonly ["shipmail_prepare_newsletter_asset_upload", "prepareNewsletterAssetUpload", "newsletters:write"], readonly ["shipmail_register_newsletter_asset", "uploadNewsletterAsset", "newsletters:write"], readonly ["shipmail_preview_newsletter", "previewNewsletter", "newsletters:read"], readonly ["shipmail_run_newsletter_preflight", "runNewsletterPreflight", "newsletters:write"], readonly ["shipmail_send_newsletter_test", "sendNewsletterTest", "newsletters:write"], readonly ["shipmail_schedule_newsletter", "scheduleNewsletter", "newsletters:write"], readonly ["shipmail_cancel_newsletter", "cancelNewsletter", "newsletters:write"], readonly ["shipmail_resume_newsletter", "resumeNewsletter", "newsletters:write"], readonly ["shipmail_list_calendar_events", "listCalendarEvents", "calendar:read"], readonly ["shipmail_create_calendar_event", "createCalendarEvent", "calendar:write"], readonly ["shipmail_get_calendar_event", "getCalendarEvent", "calendar:read"], readonly ["shipmail_update_calendar_event", "updateCalendarEvent", "calendar:write"], readonly ["shipmail_delete_calendar_event", "deleteCalendarEvent", "calendar:write"], readonly ["shipmail_get_calendar_availability", "getCalendarAvailability", "calendar:read"], readonly ["shipmail_list_booking_pages", "listBookingPages", "booking_pages:read"], readonly ["shipmail_create_booking_page", "createBookingPage", "booking_pages:write"], readonly ["shipmail_get_booking_page", "getBookingPage", "booking_pages:read"], readonly ["shipmail_update_booking_page", "updateBookingPage", "booking_pages:write"], readonly ["shipmail_delete_booking_page", "deleteBookingPage", "booking_pages:write"]];
147
147
  type McpToolName = (typeof CAPABILITY_ROWS)[number][0];
148
148
  type McpCapability = {
149
149
  readonly toolName: McpToolName;
@@ -187,6 +187,7 @@ var MCP_PERMISSION_GROUPS = [
187
187
  ];
188
188
  var CAPABILITY_ROWS = [
189
189
  ["shipmail_status", "getStatus", "public"],
190
+ ["shipmail_get_organization_access", "getOrganizationAccess", "public"],
190
191
  ["shipmail_list_automations", "listAutomations", "automations:read"],
191
192
  ["shipmail_create_automation", "createAutomation", "automations:write"],
192
193
  ["shipmail_get_automation", "getAutomation", "automations:read"],
@@ -239,7 +240,7 @@ var CAPABILITY_ROWS = [
239
240
  ["shipmail_list_mailbox_forwarding", "listMailboxForwarding", "mailbox_forwarding:read"],
240
241
  ["shipmail_create_mailbox_forwarding", "createMailboxForwarding", "mailbox_forwarding:write"],
241
242
  ["shipmail_delete_mailbox_forwarding", "deleteMailboxForwarding", "mailbox_forwarding:write"],
242
- ["shipmail_reset_mailbox_password", "resetMailboxPassword", "mailboxes:write"],
243
+ ["shipmail_reset_mailbox_password", "resetMailboxPassword", "mailbox_credentials:write"],
243
244
  ["shipmail_set_auto_reply", "updateAutoReply", "mailboxes:write"],
244
245
  ["shipmail_get_mailbox_delivery_routing", "getMailboxDeliveryRouting", "mailboxes:read"],
245
246
  ["shipmail_update_mailbox_delivery_routing", "updateMailboxDeliveryRouting", "mailboxes:write"],
package/dist/index.js CHANGED
@@ -267,6 +267,7 @@ var MCP_PERMISSION_GROUPS = [
267
267
  ];
268
268
  var CAPABILITY_ROWS = [
269
269
  ["shipmail_status", "getStatus", "public"],
270
+ ["shipmail_get_organization_access", "getOrganizationAccess", "public"],
270
271
  ["shipmail_list_automations", "listAutomations", "automations:read"],
271
272
  ["shipmail_create_automation", "createAutomation", "automations:write"],
272
273
  ["shipmail_get_automation", "getAutomation", "automations:read"],
@@ -319,7 +320,7 @@ var CAPABILITY_ROWS = [
319
320
  ["shipmail_list_mailbox_forwarding", "listMailboxForwarding", "mailbox_forwarding:read"],
320
321
  ["shipmail_create_mailbox_forwarding", "createMailboxForwarding", "mailbox_forwarding:write"],
321
322
  ["shipmail_delete_mailbox_forwarding", "deleteMailboxForwarding", "mailbox_forwarding:write"],
322
- ["shipmail_reset_mailbox_password", "resetMailboxPassword", "mailboxes:write"],
323
+ ["shipmail_reset_mailbox_password", "resetMailboxPassword", "mailbox_credentials:write"],
323
324
  ["shipmail_set_auto_reply", "updateAutoReply", "mailboxes:write"],
324
325
  ["shipmail_get_mailbox_delivery_routing", "getMailboxDeliveryRouting", "mailboxes:read"],
325
326
  ["shipmail_update_mailbox_delivery_routing", "updateMailboxDeliveryRouting", "mailboxes:write"],
@@ -754,12 +755,29 @@ function formatShipmailError(error) {
754
755
  if (error instanceof ReconciliationRequiredError && error.messageId) {
755
756
  parts.push(`message_id=${sanitizeString(error.messageId, 200)}`);
756
757
  }
758
+ const actionUrl = isSafeMessage ? safeActionUrl(error.actionUrl) : null;
759
+ if (actionUrl) {
760
+ if (error.reason) parts.push(`reason=${sanitizeString(error.reason, 64)}`);
761
+ parts.push(`action_url=${actionUrl}`);
762
+ parts.push("Send action_url to the organization owner; do not pay or choose a plan yourself.");
763
+ }
757
764
  if (isSafeMessage && error instanceof ValidationError && error.details?.length) {
758
765
  const fields = error.details.map((detail) => sanitizeString(detail.field, 100)).filter((field) => field.length > 0).slice(0, 25).join(", ");
759
766
  if (fields.length > 0) parts.push(`fields=${fields}`);
760
767
  }
761
768
  return parts.join(" | ");
762
769
  }
770
+ function safeActionUrl(value) {
771
+ if (!value) return null;
772
+ let parsed;
773
+ try {
774
+ parsed = new URL(value);
775
+ } catch {
776
+ return null;
777
+ }
778
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
779
+ return sanitizeString(parsed.href, 500);
780
+ }
763
781
  function safeMarkerStrip(message) {
764
782
  for (const marker of SAFE_MARKERS) {
765
783
  if (message.startsWith(marker)) {
@@ -968,7 +986,8 @@ var SYSTEM_FOLDER_NAMES = [
968
986
  ];
969
987
  var MAILBOX_RULE_MATCH_MODES = ["all", "any"];
970
988
  var MAILBOX_RULE_SYSTEM_TARGET_ROLES = ["inbox", "archive", "junk", "trash"];
971
- var MEMBER_ROLES = ["owner", "super_admin", "admin", "member"];
989
+ var MEMBER_ROLES = ["owner", "admin", "member"];
990
+ var MEMBER_MAILBOX_ACCESS_SCOPES = ["all", "selected"];
972
991
  var JMAP_KEYWORDS = ["$flagged", "$seen", "$draft", "$answered", "$forwarded"];
973
992
  var NEWSLETTER_STATUSES = [
974
993
  "draft",
@@ -1080,6 +1099,19 @@ var statusSchema = z.object({
1080
1099
  time: z.string(),
1081
1100
  request_id: z.string()
1082
1101
  });
1102
+ var organizationAccessSchema = z.object({
1103
+ object: z.literal("organization_access"),
1104
+ organization: z.object({ id: z.string(), name: z.string() }),
1105
+ plan: z.enum(["free", "solo", "pro", "team", "scale"]),
1106
+ has_access: z.boolean(),
1107
+ trial: z.object({
1108
+ active: z.boolean(),
1109
+ ends_at: z.string().nullable(),
1110
+ eligible: z.boolean()
1111
+ }),
1112
+ mailboxes: z.object({ limit: z.number().int(), used: z.number().int() }),
1113
+ newsletters_allowed: z.boolean()
1114
+ });
1083
1115
  var registrationSchema = z.object({
1084
1116
  expires_at: z.string(),
1085
1117
  auto_renew: z.boolean(),
@@ -1556,6 +1588,7 @@ var mailboxForwardingSchema = z.object({
1556
1588
  mailbox_id: z.string(),
1557
1589
  destination: emailSchema,
1558
1590
  sender: emailSchema.nullable(),
1591
+ recipient: emailSchema.nullable(),
1559
1592
  status: z.enum(["pending", "active"]),
1560
1593
  verification_sent_at: z.string().nullable(),
1561
1594
  verified_at: z.string().nullable(),
@@ -1767,12 +1800,22 @@ var webhookSchema = z.object({
1767
1800
  created_at: z.string(),
1768
1801
  updated_at: z.string()
1769
1802
  });
1803
+ var memberMailboxAccessSchema = z.object({
1804
+ scope: z.enum(MEMBER_MAILBOX_ACCESS_SCOPES),
1805
+ mailbox_ids: z.array(z.string()).describe(
1806
+ 'Mailbox IDs visible to this API credential. Empty when scope is "all"; for "selected", the list can be partial when the credential reaches only some granted mailboxes.'
1807
+ )
1808
+ }).refine((access) => access.scope !== "all" || access.mailbox_ids.length === 0, {
1809
+ message: 'mailbox_ids must be empty when scope is "all".',
1810
+ path: ["mailbox_ids"]
1811
+ });
1770
1812
  var memberSchema = z.object({
1771
1813
  object: z.literal("member"),
1772
1814
  id: z.string(),
1773
1815
  email: z.string(),
1774
1816
  name: z.string(),
1775
1817
  role: z.enum(MEMBER_ROLES),
1818
+ mailbox_access: memberMailboxAccessSchema,
1776
1819
  created_at: z.string()
1777
1820
  });
1778
1821
  var webhookWithSecretSchema = webhookSchema.extend({
@@ -1812,6 +1855,7 @@ var statusOutputSchema = z.object({
1812
1855
  // organization_id on other tools.
1813
1856
  organizations: z.array(z.object({ id: z.string(), name: z.string() })).optional()
1814
1857
  });
1858
+ var organizationAccessOutputSchema = z.object({ access: organizationAccessSchema });
1815
1859
  var domainOutputSchema = z.object({ domain: domainSchema });
1816
1860
  var domainDnsRecordsOutputSchema = z.object({ dns_records: domainDnsRecordSetSchema });
1817
1861
  var mailboxOutputSchema = z.object({ mailbox: mailboxSchema });
@@ -2167,6 +2211,7 @@ var createMailboxForwardingInputSchema = z.object({
2167
2211
  id: idSchema,
2168
2212
  destination: emailSchema,
2169
2213
  sender: emailSchema.nullable().optional(),
2214
+ recipient: emailSchema.nullable().optional(),
2170
2215
  idempotency_key: idempotencyKeySchema
2171
2216
  });
2172
2217
  var deleteMailboxForwardingInputSchema = z.object({
@@ -2813,6 +2858,13 @@ var newsletterSchema = z.object({
2813
2858
  styling_mode: z.enum(NEWSLETTER_STYLING_MODES).describe(
2814
2859
  "styled applies Shipmail's email theme. plain sends your HTML without injected styles, width, or centering, so the reader's email client styles it."
2815
2860
  ),
2861
+ track_engagement: z.boolean().describe("Whether this issue tracks opens and clicks."),
2862
+ opened_count: z.number().int().nullable().describe(
2863
+ "Unique recipients with at least one counted open, excluding Apple Mail Privacy Protection preloads. Null when track_engagement is false."
2864
+ ),
2865
+ clicked_count: z.number().int().nullable().describe(
2866
+ "Unique recipients who clicked at least one tracked link, excluding link scanners. Null when track_engagement is false."
2867
+ ),
2816
2868
  preflight_status: z.enum(NEWSLETTER_PREFLIGHT_STATUSES),
2817
2869
  preflight_results: z.record(z.string(), z.unknown()),
2818
2870
  send_window_hours: z.number().int(),
@@ -3086,6 +3138,9 @@ var newsletterDraftFieldsInputSchema = {
3086
3138
  ),
3087
3139
  styling_mode: z.enum(NEWSLETTER_STYLING_MODES).optional().describe(
3088
3140
  "styled applies Shipmail's email theme. plain sends your HTML without injected styles, width, or centering, so the reader's email client styles it."
3141
+ ),
3142
+ track_engagement: z.boolean().optional().describe(
3143
+ "Track opens and clicks for this issue. Off by default; omit on update to keep the current value. Fails with validation_error when open and click tracking is not available. Changes only while the newsletter is an editable draft or a future scheduled newsletter."
3089
3144
  )
3090
3145
  };
3091
3146
  var createNewsletterInputSchema = z.object({
@@ -3156,9 +3211,10 @@ var updateNewsletterInputSchema = z.object({
3156
3211
  archive_visibility: newsletterDraftFieldsInputSchema.archive_visibility,
3157
3212
  feed_entry_url: newsletterDraftFieldsInputSchema.feed_entry_url,
3158
3213
  styling_mode: newsletterDraftFieldsInputSchema.styling_mode,
3214
+ track_engagement: newsletterDraftFieldsInputSchema.track_engagement,
3159
3215
  idempotency_key: idempotencyKeySchema
3160
3216
  }).refine(
3161
- (value) => value.audience_id !== void 0 || value.sender_identity_id !== void 0 || value.name !== void 0 || value.subject !== void 0 || value.preview_text !== void 0 || value.body_html !== void 0 || value.body_text !== void 0 || value.blocks !== void 0 || value.send_window_hours !== void 0 || value.archive_visibility !== void 0 || value.feed_entry_url !== void 0 || value.styling_mode !== void 0,
3217
+ (value) => value.audience_id !== void 0 || value.sender_identity_id !== void 0 || value.name !== void 0 || value.subject !== void 0 || value.preview_text !== void 0 || value.body_html !== void 0 || value.body_text !== void 0 || value.blocks !== void 0 || value.send_window_hours !== void 0 || value.archive_visibility !== void 0 || value.feed_entry_url !== void 0 || value.styling_mode !== void 0 || value.track_engagement !== void 0,
3162
3218
  {
3163
3219
  message: "Provide at least one newsletter field to update."
3164
3220
  }
@@ -3300,6 +3356,7 @@ var calendarInvitationLanguageSchema = z.enum(CALENDAR_INVITATION_LANGUAGES).des
3300
3356
  var calendarEventSchema = z.object({
3301
3357
  object: z.literal("calendar_event"),
3302
3358
  id: z.string(),
3359
+ revision: z.string(),
3303
3360
  mailbox: z.string(),
3304
3361
  calendar_id: z.string().nullable(),
3305
3362
  uid: z.string().nullable(),
@@ -3325,6 +3382,14 @@ var calendarEventSchema = z.object({
3325
3382
  created_at: z.string().nullable(),
3326
3383
  updated_at: z.string().nullable()
3327
3384
  });
3385
+ var calendarInvitationOutcomeSchema = z.object({
3386
+ recipient: z.string(),
3387
+ status: z.enum(["sent", "failed", "unknown"])
3388
+ });
3389
+ var calendarEventMutationSchema = calendarEventSchema.extend({
3390
+ invitation_outcomes: z.array(calendarInvitationOutcomeSchema),
3391
+ invitation_failures: z.array(z.string())
3392
+ });
3328
3393
  var calendarAvailabilitySlotSchema = z.object({
3329
3394
  start: z.string(),
3330
3395
  end: z.string()
@@ -3551,6 +3616,7 @@ var bookingPageSchema = z.object({
3551
3616
  updated_at: z.string()
3552
3617
  });
3553
3618
  var calendarEventOutputSchema = z.object({ event: calendarEventSchema });
3619
+ var calendarEventMutationOutputSchema = z.object({ event: calendarEventMutationSchema });
3554
3620
  var calendarEventsOutputSchema = z.object({
3555
3621
  data: z.array(calendarEventSchema),
3556
3622
  pagination: paginationSchema
@@ -3578,6 +3644,8 @@ var attendeeInputSchema = z.object({
3578
3644
  name: noControlString(255, "attendee name").optional()
3579
3645
  });
3580
3646
  var mailboxAddressInputSchema = emailSchema.describe("The mailbox (calendar owner) address.");
3647
+ var calendarOperationKeySchema = z.string().min(16).max(200).regex(/^[A-Za-z0-9._:-]+$/).describe("Stable retry key for this exact calendar mutation payload.");
3648
+ var calendarRevisionSchema = z.string().regex(/^[a-f0-9]{64}$/).describe("Revision originally read before updating the event.");
3581
3649
  var listCalendarEventsInputSchema = paginationInputSchema.extend({
3582
3650
  mailbox: mailboxAddressInputSchema,
3583
3651
  from: utcInstantSchema.describe("Start of the time range (UTC instant)."),
@@ -3595,6 +3663,8 @@ var deleteCalendarEventInputSchema = z.object({
3595
3663
  });
3596
3664
  var createCalendarEventInputSchema = z.object({
3597
3665
  mailbox: mailboxAddressInputSchema,
3666
+ operation_key: calendarOperationKeySchema.optional(),
3667
+ send_invitations: z.boolean().default(true).describe("Send invitations to attendees (default true)."),
3598
3668
  calendar_id: calendarIdInputSchema.optional().describe("Target calendar. Defaults to the default calendar."),
3599
3669
  title: noControlString(1024, "title").min(1),
3600
3670
  invitation_language: calendarInvitationLanguageSchema.optional(),
@@ -3617,6 +3687,9 @@ var createCalendarEventInputSchema = z.object({
3617
3687
  var updateCalendarEventInputSchema = z.object({
3618
3688
  id: calendarEventIdInputSchema.describe("Calendar event ID."),
3619
3689
  mailbox: mailboxAddressInputSchema,
3690
+ operation_key: calendarOperationKeySchema.optional(),
3691
+ expected_revision: calendarRevisionSchema.optional(),
3692
+ send_guest_updates: z.boolean().default(true).describe("Send scheduling updates to attendees (default true)."),
3620
3693
  title: noControlString(1024, "title").min(1).optional(),
3621
3694
  invitation_language: calendarInvitationLanguageSchema.optional(),
3622
3695
  description: noControlString(32768, "description").nullish(),
@@ -4188,6 +4261,10 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4188
4261
  var bridge = window.openai;
4189
4262
  var input = bridge && bridge.toolInput ? bridge.toolInput : {};
4190
4263
  var selectedFile = input.file || null;
4264
+ // Once the send tool has been called, its outcome can be ambiguous to
4265
+ // the card (for example, the host can lose the response after accepting
4266
+ // the request). Keep this exact payload until it resolves.
4267
+ var pendingSend = null;
4191
4268
  var submit = document.getElementById("submit");
4192
4269
  var change = document.getElementById("change");
4193
4270
  var status = document.getElementById("status");
@@ -4209,7 +4286,9 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4209
4286
  }
4210
4287
  function setBusy(busy) {
4211
4288
  submit.disabled = busy;
4212
- change.disabled = busy;
4289
+ // A different file would turn an uncertain, already-accepted request
4290
+ // into a new one. It stays unavailable until this request resolves.
4291
+ change.disabled = busy || Boolean(pendingSend);
4213
4292
  }
4214
4293
  function readUrl(value) {
4215
4294
  if (typeof value === "string") return value;
@@ -4243,8 +4322,12 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4243
4322
  if (bridge && typeof bridge.selectFiles === "function") {
4244
4323
  change.hidden = false;
4245
4324
  change.addEventListener("click", async function () {
4325
+ if (pendingSend) return;
4246
4326
  try {
4247
4327
  var files = await bridge.selectFiles();
4328
+ // The picker may have opened before a send crossed its boundary.
4329
+ // Do not let its late result replace the retained request.
4330
+ if (pendingSend) return;
4248
4331
  if (files && files[0]) {
4249
4332
  selectedFile = files[0];
4250
4333
  text("file", fileName(selectedFile));
@@ -4268,6 +4351,15 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4268
4351
 
4269
4352
  setBusy(true);
4270
4353
  try {
4354
+ if (pendingSend) {
4355
+ setStatus(input.scheduled_at ? "Checking the scheduled message..." : "Checking the message send...");
4356
+ var retried = await bridge.callTool("shipmail_send_message", pendingSend);
4357
+ if (hasToolError(retried)) throw new Error("send_failed");
4358
+ setStatus(input.scheduled_at ? "Message scheduled." : "Message sent.", "success");
4359
+ submit.hidden = true;
4360
+ change.hidden = true;
4361
+ return;
4362
+ }
4271
4363
  setStatus("Downloading the selected file...");
4272
4364
  var fileId = selectedFile.file_id || selectedFile.fileId;
4273
4365
  var downloadUrl = selectedFile.download_url || selectedFile.downloadUrl || null;
@@ -4325,13 +4417,22 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4325
4417
  idempotency_key: "mcp_app_" + crypto.randomUUID().replace(/-/g, "")
4326
4418
  });
4327
4419
  delete sendInput.file;
4328
- var sent = await bridge.callTool("shipmail_send_message", sendInput);
4420
+ pendingSend = sendInput;
4421
+ submit.textContent = input.scheduled_at ? "Check scheduled result" : "Check send result";
4422
+ var sent = await bridge.callTool("shipmail_send_message", pendingSend);
4329
4423
  if (hasToolError(sent)) throw new Error("send_failed");
4330
4424
  setStatus(input.scheduled_at ? "Message scheduled." : "Message sent.", "success");
4331
4425
  submit.hidden = true;
4332
4426
  change.hidden = true;
4333
4427
  } catch (error) {
4334
- setStatus("The attachment could not be sent. No automatic retry was made.", "error");
4428
+ setStatus(
4429
+ pendingSend
4430
+ ? input.scheduled_at
4431
+ ? "The scheduling result is unknown. Check Scheduled Messages before retrying; retry uses the same request."
4432
+ : "The send result is unknown. Check Sent before retrying; retry uses the same request."
4433
+ : "The attachment could not be prepared for sending.",
4434
+ "error"
4435
+ );
4335
4436
  } finally {
4336
4437
  setBusy(false);
4337
4438
  }
@@ -5313,6 +5414,20 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
5313
5414
  }))
5314
5415
  );
5315
5416
  });
5417
+ registerIfAllowed("shipmail_get_organization_access", () => {
5418
+ server.registerTool(
5419
+ "shipmail_get_organization_access",
5420
+ {
5421
+ title: "Get Organization Access",
5422
+ description: "Check whether the organization can create mailboxes now: plan, has_access, trial state and end, trial eligibility, mailbox limit and usage, and whether newsletters are allowed. Poll it after the owner opens the billing link: access appears once Shipmail has recorded the payment. Never choose or pay for a plan yourself.",
5423
+ outputSchema: organizationAccessOutputSchema,
5424
+ annotations: { readOnlyHint: true, openWorldHint: false }
5425
+ },
5426
+ async () => runTool("shipmail_get_organization_access", organizationAccessOutputSchema, async () => ({
5427
+ access: await client.organization.access()
5428
+ }))
5429
+ );
5430
+ });
5316
5431
  registerIfAllowed("shipmail_list_domains", () => {
5317
5432
  server.registerTool(
5318
5433
  "shipmail_list_domains",
@@ -5350,7 +5465,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
5350
5465
  "shipmail_get_domain_dns_records",
5351
5466
  {
5352
5467
  title: "Get Domain DNS Records",
5353
- description: "Return all six DNS records required by Shipmail and live observed values for propagation diagnostics. This does not update domain state.",
5468
+ description: "Return the DNS records Shipmail requires for this domain and live observed values for propagation diagnostics. A connected domain needs four: MX, SPF, DKIM and DMARC. A domain bought through Shipmail also lists two mail-subdomain records, which Shipmail adds itself. This does not update domain state.",
5354
5469
  inputSchema: getByIdInputSchema,
5355
5470
  outputSchema: domainDnsRecordsOutputSchema,
5356
5471
  annotations: { readOnlyHint: true, openWorldHint: true }
@@ -6530,7 +6645,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
6530
6645
  "shipmail_create_mailbox_forwarding",
6531
6646
  {
6532
6647
  title: "Add Mailbox Forwarding",
6533
- description: "Send a confirmation email to a forwarding destination. Delivery begins after recipient confirmation, keeps a local copy, and excludes spam.",
6648
+ description: "Send a confirmation email to a forwarding destination. Optionally filter by exact From address, delivery recipient, or both. Delivery begins after confirmation, keeps a local copy, and excludes spam.",
6534
6649
  inputSchema: createMailboxForwardingInputSchema,
6535
6650
  outputSchema: mailboxForwardingOutputSchema,
6536
6651
  annotations: {
@@ -6543,7 +6658,11 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
6543
6658
  async (args) => runTool("shipmail_create_mailbox_forwarding", mailboxForwardingOutputSchema, async () => ({
6544
6659
  forwarding: await client.mailboxes.createForwarding(
6545
6660
  args.id,
6546
- { destination: args.destination, sender: args.sender ?? null },
6661
+ {
6662
+ destination: args.destination,
6663
+ sender: args.sender ?? null,
6664
+ recipient: args.recipient ?? null
6665
+ },
6547
6666
  mutationOptions(args)
6548
6667
  )
6549
6668
  }))
@@ -7081,7 +7200,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7081
7200
  "shipmail_list_members",
7082
7201
  {
7083
7202
  title: "List Members",
7084
- description: "List organization members.",
7203
+ description: "List organization members and their mailbox access. Selected mailbox IDs are limited to mailboxes visible to this API credential and may be partial.",
7085
7204
  inputSchema: listMembersInputSchema,
7086
7205
  outputSchema: membersOutputSchema,
7087
7206
  annotations: { readOnlyHint: true, openWorldHint: false }
@@ -7098,7 +7217,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7098
7217
  "shipmail_get_member",
7099
7218
  {
7100
7219
  title: "Get Member",
7101
- description: "Fetch an organization member by ID.",
7220
+ description: "Fetch an organization member and their mailbox access by ID. Selected mailbox IDs are limited to mailboxes visible to this API credential and may be partial.",
7102
7221
  inputSchema: getByIdInputSchema,
7103
7222
  outputSchema: memberOutputSchema,
7104
7223
  annotations: { readOnlyHint: true, openWorldHint: false }
@@ -7580,7 +7699,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7580
7699
  "shipmail_create_newsletter",
7581
7700
  {
7582
7701
  title: "Create Newsletter",
7583
- description: "Create a newsletter draft for an audience and sender identity. Shipmail renders blocks to email-safe HTML and text. Paragraph, quote, callout, list-item, and column bodies accept text or sanitized inline HTML. styled applies Shipmail's email theme. plain preserves HTML without injected styles, width, or centering.",
7702
+ description: "Create a newsletter draft for an audience and sender identity. Shipmail renders blocks to email-safe HTML and text. Paragraph, quote, callout, list-item, and column bodies accept text or sanitized inline HTML. styled applies Shipmail's email theme. plain preserves HTML without injected styles, width, or centering. track_engagement turns on open and click tracking for this issue; it is off by default.",
7584
7703
  inputSchema: createNewsletterInputSchema,
7585
7704
  outputSchema: newsletterOutputSchema,
7586
7705
  annotations: {
@@ -7626,7 +7745,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7626
7745
  "shipmail_update_newsletter",
7627
7746
  {
7628
7747
  title: "Update Newsletter",
7629
- description: "Update an editable newsletter draft or future scheduled newsletter. Paragraph, quote, callout, list-item, and column bodies accept text or sanitized inline HTML. body_text alone updates the plain-text override when blocks exist. Sending and sent newsletters cannot be edited. Concurrent saves return conflict (409). styled applies Shipmail's email theme. plain preserves HTML without injected styles, width, or centering.",
7748
+ description: "Update an editable newsletter draft or future scheduled newsletter. Changing message content, presentation, or audience returns a scheduled newsletter to draft and clears scheduled_at; inspect the returned status, send a new test, and schedule again. Name, feed link, and send-window changes can keep the schedule. Paragraph, quote, callout, list-item, and column bodies accept text or sanitized inline HTML. body_text alone updates the plain-text override when blocks exist. Sending and sent newsletters cannot be edited. Concurrent saves return conflict (409). styled applies Shipmail's email theme. plain preserves HTML without injected styles, width, or centering. track_engagement turns open and click tracking on or off for this issue.",
7630
7749
  inputSchema: updateNewsletterInputSchema,
7631
7750
  outputSchema: newsletterOutputSchema,
7632
7751
  annotations: {
@@ -7653,7 +7772,8 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7653
7772
  ...rest.send_window_hours !== void 0 ? { send_window_hours: rest.send_window_hours } : {},
7654
7773
  ...rest.archive_visibility !== void 0 ? { archive_visibility: rest.archive_visibility } : {},
7655
7774
  ...rest.feed_entry_url !== void 0 ? { feed_entry_url: rest.feed_entry_url } : {},
7656
- ...rest.styling_mode !== void 0 ? { styling_mode: rest.styling_mode } : {}
7775
+ ...rest.styling_mode !== void 0 ? { styling_mode: rest.styling_mode } : {},
7776
+ ...rest.track_engagement !== void 0 ? { track_engagement: rest.track_engagement } : {}
7657
7777
  },
7658
7778
  mutationOptions(args)
7659
7779
  )
@@ -8183,9 +8303,9 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8183
8303
  "shipmail_create_calendar_event",
8184
8304
  {
8185
8305
  title: "Create Calendar Event",
8186
- description: "Create a calendar event on a mailbox's calendar. start is a local date-time; its zone is given by timezone.",
8306
+ description: "Create a calendar event on a mailbox's calendar. start is a local date-time; its zone is given by timezone. Reuse operation_key only when retrying the exact same payload.",
8187
8307
  inputSchema: createCalendarEventInputSchema,
8188
- outputSchema: calendarEventOutputSchema,
8308
+ outputSchema: calendarEventMutationOutputSchema,
8189
8309
  annotations: {
8190
8310
  readOnlyHint: false,
8191
8311
  destructiveHint: false,
@@ -8193,7 +8313,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8193
8313
  openWorldHint: false
8194
8314
  }
8195
8315
  },
8196
- async (args) => runTool("shipmail_create_calendar_event", calendarEventOutputSchema, async () => ({
8316
+ async (args) => runTool("shipmail_create_calendar_event", calendarEventMutationOutputSchema, async () => ({
8197
8317
  event: await client.calendar.events.create(
8198
8318
  stripIdempotencyKey(args),
8199
8319
  mutationOptions(args)
@@ -8206,9 +8326,9 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8206
8326
  "shipmail_update_calendar_event",
8207
8327
  {
8208
8328
  title: "Update Calendar Event",
8209
- description: "Update a calendar event. Omitted fields are unchanged; send null to clear description, timezone, location, video_url, recurrence, or reminders.",
8329
+ description: "Update a calendar event. Omitted fields are unchanged; send null to clear description, timezone, location, video_url, recurrence, or reminders. Use expected_revision from a prior read and reuse operation_key only for an exact-payload retry.",
8210
8330
  inputSchema: updateCalendarEventInputSchema,
8211
- outputSchema: calendarEventOutputSchema,
8331
+ outputSchema: calendarEventMutationOutputSchema,
8212
8332
  annotations: {
8213
8333
  readOnlyHint: false,
8214
8334
  destructiveHint: false,
@@ -8216,7 +8336,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8216
8336
  openWorldHint: false
8217
8337
  }
8218
8338
  },
8219
- async (args) => runTool("shipmail_update_calendar_event", calendarEventOutputSchema, async () => {
8339
+ async (args) => runTool("shipmail_update_calendar_event", calendarEventMutationOutputSchema, async () => {
8220
8340
  const { id, idempotency_key: _key, ...params } = args;
8221
8341
  return { event: await client.calendar.events.update(id, params, mutationOptions(args)) };
8222
8342
  })
@@ -8468,7 +8588,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8468
8588
  }
8469
8589
 
8470
8590
  // src/version.ts
8471
- var VERSION = "0.9.1";
8591
+ var VERSION = "0.9.3";
8472
8592
 
8473
8593
  // src/server.ts
8474
8594
  var SHIPMAIL_MCP_INSTRUCTIONS = `Shipmail MCP exposes the business email and calendar tools authorized by the connection's current Shipmail permissions.
package/dist/server.js CHANGED
@@ -173,6 +173,7 @@ var MCP_PERMISSION_GROUPS = [
173
173
  ];
174
174
  var CAPABILITY_ROWS = [
175
175
  ["shipmail_status", "getStatus", "public"],
176
+ ["shipmail_get_organization_access", "getOrganizationAccess", "public"],
176
177
  ["shipmail_list_automations", "listAutomations", "automations:read"],
177
178
  ["shipmail_create_automation", "createAutomation", "automations:write"],
178
179
  ["shipmail_get_automation", "getAutomation", "automations:read"],
@@ -225,7 +226,7 @@ var CAPABILITY_ROWS = [
225
226
  ["shipmail_list_mailbox_forwarding", "listMailboxForwarding", "mailbox_forwarding:read"],
226
227
  ["shipmail_create_mailbox_forwarding", "createMailboxForwarding", "mailbox_forwarding:write"],
227
228
  ["shipmail_delete_mailbox_forwarding", "deleteMailboxForwarding", "mailbox_forwarding:write"],
228
- ["shipmail_reset_mailbox_password", "resetMailboxPassword", "mailboxes:write"],
229
+ ["shipmail_reset_mailbox_password", "resetMailboxPassword", "mailbox_credentials:write"],
229
230
  ["shipmail_set_auto_reply", "updateAutoReply", "mailboxes:write"],
230
231
  ["shipmail_get_mailbox_delivery_routing", "getMailboxDeliveryRouting", "mailboxes:read"],
231
232
  ["shipmail_update_mailbox_delivery_routing", "updateMailboxDeliveryRouting", "mailboxes:write"],
@@ -660,12 +661,29 @@ function formatShipmailError(error) {
660
661
  if (error instanceof ReconciliationRequiredError && error.messageId) {
661
662
  parts.push(`message_id=${sanitizeString(error.messageId, 200)}`);
662
663
  }
664
+ const actionUrl = isSafeMessage ? safeActionUrl(error.actionUrl) : null;
665
+ if (actionUrl) {
666
+ if (error.reason) parts.push(`reason=${sanitizeString(error.reason, 64)}`);
667
+ parts.push(`action_url=${actionUrl}`);
668
+ parts.push("Send action_url to the organization owner; do not pay or choose a plan yourself.");
669
+ }
663
670
  if (isSafeMessage && error instanceof ValidationError && error.details?.length) {
664
671
  const fields = error.details.map((detail) => sanitizeString(detail.field, 100)).filter((field) => field.length > 0).slice(0, 25).join(", ");
665
672
  if (fields.length > 0) parts.push(`fields=${fields}`);
666
673
  }
667
674
  return parts.join(" | ");
668
675
  }
676
+ function safeActionUrl(value) {
677
+ if (!value) return null;
678
+ let parsed;
679
+ try {
680
+ parsed = new URL(value);
681
+ } catch {
682
+ return null;
683
+ }
684
+ if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
685
+ return sanitizeString(parsed.href, 500);
686
+ }
669
687
  function safeMarkerStrip(message) {
670
688
  for (const marker of SAFE_MARKERS) {
671
689
  if (message.startsWith(marker)) {
@@ -874,7 +892,8 @@ var SYSTEM_FOLDER_NAMES = [
874
892
  ];
875
893
  var MAILBOX_RULE_MATCH_MODES = ["all", "any"];
876
894
  var MAILBOX_RULE_SYSTEM_TARGET_ROLES = ["inbox", "archive", "junk", "trash"];
877
- var MEMBER_ROLES = ["owner", "super_admin", "admin", "member"];
895
+ var MEMBER_ROLES = ["owner", "admin", "member"];
896
+ var MEMBER_MAILBOX_ACCESS_SCOPES = ["all", "selected"];
878
897
  var JMAP_KEYWORDS = ["$flagged", "$seen", "$draft", "$answered", "$forwarded"];
879
898
  var NEWSLETTER_STATUSES = [
880
899
  "draft",
@@ -986,6 +1005,19 @@ var statusSchema = z.object({
986
1005
  time: z.string(),
987
1006
  request_id: z.string()
988
1007
  });
1008
+ var organizationAccessSchema = z.object({
1009
+ object: z.literal("organization_access"),
1010
+ organization: z.object({ id: z.string(), name: z.string() }),
1011
+ plan: z.enum(["free", "solo", "pro", "team", "scale"]),
1012
+ has_access: z.boolean(),
1013
+ trial: z.object({
1014
+ active: z.boolean(),
1015
+ ends_at: z.string().nullable(),
1016
+ eligible: z.boolean()
1017
+ }),
1018
+ mailboxes: z.object({ limit: z.number().int(), used: z.number().int() }),
1019
+ newsletters_allowed: z.boolean()
1020
+ });
989
1021
  var registrationSchema = z.object({
990
1022
  expires_at: z.string(),
991
1023
  auto_renew: z.boolean(),
@@ -1462,6 +1494,7 @@ var mailboxForwardingSchema = z.object({
1462
1494
  mailbox_id: z.string(),
1463
1495
  destination: emailSchema,
1464
1496
  sender: emailSchema.nullable(),
1497
+ recipient: emailSchema.nullable(),
1465
1498
  status: z.enum(["pending", "active"]),
1466
1499
  verification_sent_at: z.string().nullable(),
1467
1500
  verified_at: z.string().nullable(),
@@ -1673,12 +1706,22 @@ var webhookSchema = z.object({
1673
1706
  created_at: z.string(),
1674
1707
  updated_at: z.string()
1675
1708
  });
1709
+ var memberMailboxAccessSchema = z.object({
1710
+ scope: z.enum(MEMBER_MAILBOX_ACCESS_SCOPES),
1711
+ mailbox_ids: z.array(z.string()).describe(
1712
+ 'Mailbox IDs visible to this API credential. Empty when scope is "all"; for "selected", the list can be partial when the credential reaches only some granted mailboxes.'
1713
+ )
1714
+ }).refine((access) => access.scope !== "all" || access.mailbox_ids.length === 0, {
1715
+ message: 'mailbox_ids must be empty when scope is "all".',
1716
+ path: ["mailbox_ids"]
1717
+ });
1676
1718
  var memberSchema = z.object({
1677
1719
  object: z.literal("member"),
1678
1720
  id: z.string(),
1679
1721
  email: z.string(),
1680
1722
  name: z.string(),
1681
1723
  role: z.enum(MEMBER_ROLES),
1724
+ mailbox_access: memberMailboxAccessSchema,
1682
1725
  created_at: z.string()
1683
1726
  });
1684
1727
  var webhookWithSecretSchema = webhookSchema.extend({
@@ -1718,6 +1761,7 @@ var statusOutputSchema = z.object({
1718
1761
  // organization_id on other tools.
1719
1762
  organizations: z.array(z.object({ id: z.string(), name: z.string() })).optional()
1720
1763
  });
1764
+ var organizationAccessOutputSchema = z.object({ access: organizationAccessSchema });
1721
1765
  var domainOutputSchema = z.object({ domain: domainSchema });
1722
1766
  var domainDnsRecordsOutputSchema = z.object({ dns_records: domainDnsRecordSetSchema });
1723
1767
  var mailboxOutputSchema = z.object({ mailbox: mailboxSchema });
@@ -2073,6 +2117,7 @@ var createMailboxForwardingInputSchema = z.object({
2073
2117
  id: idSchema,
2074
2118
  destination: emailSchema,
2075
2119
  sender: emailSchema.nullable().optional(),
2120
+ recipient: emailSchema.nullable().optional(),
2076
2121
  idempotency_key: idempotencyKeySchema
2077
2122
  });
2078
2123
  var deleteMailboxForwardingInputSchema = z.object({
@@ -2719,6 +2764,13 @@ var newsletterSchema = z.object({
2719
2764
  styling_mode: z.enum(NEWSLETTER_STYLING_MODES).describe(
2720
2765
  "styled applies Shipmail's email theme. plain sends your HTML without injected styles, width, or centering, so the reader's email client styles it."
2721
2766
  ),
2767
+ track_engagement: z.boolean().describe("Whether this issue tracks opens and clicks."),
2768
+ opened_count: z.number().int().nullable().describe(
2769
+ "Unique recipients with at least one counted open, excluding Apple Mail Privacy Protection preloads. Null when track_engagement is false."
2770
+ ),
2771
+ clicked_count: z.number().int().nullable().describe(
2772
+ "Unique recipients who clicked at least one tracked link, excluding link scanners. Null when track_engagement is false."
2773
+ ),
2722
2774
  preflight_status: z.enum(NEWSLETTER_PREFLIGHT_STATUSES),
2723
2775
  preflight_results: z.record(z.string(), z.unknown()),
2724
2776
  send_window_hours: z.number().int(),
@@ -2992,6 +3044,9 @@ var newsletterDraftFieldsInputSchema = {
2992
3044
  ),
2993
3045
  styling_mode: z.enum(NEWSLETTER_STYLING_MODES).optional().describe(
2994
3046
  "styled applies Shipmail's email theme. plain sends your HTML without injected styles, width, or centering, so the reader's email client styles it."
3047
+ ),
3048
+ track_engagement: z.boolean().optional().describe(
3049
+ "Track opens and clicks for this issue. Off by default; omit on update to keep the current value. Fails with validation_error when open and click tracking is not available. Changes only while the newsletter is an editable draft or a future scheduled newsletter."
2995
3050
  )
2996
3051
  };
2997
3052
  var createNewsletterInputSchema = z.object({
@@ -3062,9 +3117,10 @@ var updateNewsletterInputSchema = z.object({
3062
3117
  archive_visibility: newsletterDraftFieldsInputSchema.archive_visibility,
3063
3118
  feed_entry_url: newsletterDraftFieldsInputSchema.feed_entry_url,
3064
3119
  styling_mode: newsletterDraftFieldsInputSchema.styling_mode,
3120
+ track_engagement: newsletterDraftFieldsInputSchema.track_engagement,
3065
3121
  idempotency_key: idempotencyKeySchema
3066
3122
  }).refine(
3067
- (value) => value.audience_id !== void 0 || value.sender_identity_id !== void 0 || value.name !== void 0 || value.subject !== void 0 || value.preview_text !== void 0 || value.body_html !== void 0 || value.body_text !== void 0 || value.blocks !== void 0 || value.send_window_hours !== void 0 || value.archive_visibility !== void 0 || value.feed_entry_url !== void 0 || value.styling_mode !== void 0,
3123
+ (value) => value.audience_id !== void 0 || value.sender_identity_id !== void 0 || value.name !== void 0 || value.subject !== void 0 || value.preview_text !== void 0 || value.body_html !== void 0 || value.body_text !== void 0 || value.blocks !== void 0 || value.send_window_hours !== void 0 || value.archive_visibility !== void 0 || value.feed_entry_url !== void 0 || value.styling_mode !== void 0 || value.track_engagement !== void 0,
3068
3124
  {
3069
3125
  message: "Provide at least one newsletter field to update."
3070
3126
  }
@@ -3206,6 +3262,7 @@ var calendarInvitationLanguageSchema = z.enum(CALENDAR_INVITATION_LANGUAGES).des
3206
3262
  var calendarEventSchema = z.object({
3207
3263
  object: z.literal("calendar_event"),
3208
3264
  id: z.string(),
3265
+ revision: z.string(),
3209
3266
  mailbox: z.string(),
3210
3267
  calendar_id: z.string().nullable(),
3211
3268
  uid: z.string().nullable(),
@@ -3231,6 +3288,14 @@ var calendarEventSchema = z.object({
3231
3288
  created_at: z.string().nullable(),
3232
3289
  updated_at: z.string().nullable()
3233
3290
  });
3291
+ var calendarInvitationOutcomeSchema = z.object({
3292
+ recipient: z.string(),
3293
+ status: z.enum(["sent", "failed", "unknown"])
3294
+ });
3295
+ var calendarEventMutationSchema = calendarEventSchema.extend({
3296
+ invitation_outcomes: z.array(calendarInvitationOutcomeSchema),
3297
+ invitation_failures: z.array(z.string())
3298
+ });
3234
3299
  var calendarAvailabilitySlotSchema = z.object({
3235
3300
  start: z.string(),
3236
3301
  end: z.string()
@@ -3457,6 +3522,7 @@ var bookingPageSchema = z.object({
3457
3522
  updated_at: z.string()
3458
3523
  });
3459
3524
  var calendarEventOutputSchema = z.object({ event: calendarEventSchema });
3525
+ var calendarEventMutationOutputSchema = z.object({ event: calendarEventMutationSchema });
3460
3526
  var calendarEventsOutputSchema = z.object({
3461
3527
  data: z.array(calendarEventSchema),
3462
3528
  pagination: paginationSchema
@@ -3484,6 +3550,8 @@ var attendeeInputSchema = z.object({
3484
3550
  name: noControlString(255, "attendee name").optional()
3485
3551
  });
3486
3552
  var mailboxAddressInputSchema = emailSchema.describe("The mailbox (calendar owner) address.");
3553
+ var calendarOperationKeySchema = z.string().min(16).max(200).regex(/^[A-Za-z0-9._:-]+$/).describe("Stable retry key for this exact calendar mutation payload.");
3554
+ var calendarRevisionSchema = z.string().regex(/^[a-f0-9]{64}$/).describe("Revision originally read before updating the event.");
3487
3555
  var listCalendarEventsInputSchema = paginationInputSchema.extend({
3488
3556
  mailbox: mailboxAddressInputSchema,
3489
3557
  from: utcInstantSchema.describe("Start of the time range (UTC instant)."),
@@ -3501,6 +3569,8 @@ var deleteCalendarEventInputSchema = z.object({
3501
3569
  });
3502
3570
  var createCalendarEventInputSchema = z.object({
3503
3571
  mailbox: mailboxAddressInputSchema,
3572
+ operation_key: calendarOperationKeySchema.optional(),
3573
+ send_invitations: z.boolean().default(true).describe("Send invitations to attendees (default true)."),
3504
3574
  calendar_id: calendarIdInputSchema.optional().describe("Target calendar. Defaults to the default calendar."),
3505
3575
  title: noControlString(1024, "title").min(1),
3506
3576
  invitation_language: calendarInvitationLanguageSchema.optional(),
@@ -3523,6 +3593,9 @@ var createCalendarEventInputSchema = z.object({
3523
3593
  var updateCalendarEventInputSchema = z.object({
3524
3594
  id: calendarEventIdInputSchema.describe("Calendar event ID."),
3525
3595
  mailbox: mailboxAddressInputSchema,
3596
+ operation_key: calendarOperationKeySchema.optional(),
3597
+ expected_revision: calendarRevisionSchema.optional(),
3598
+ send_guest_updates: z.boolean().default(true).describe("Send scheduling updates to attendees (default true)."),
3526
3599
  title: noControlString(1024, "title").min(1).optional(),
3527
3600
  invitation_language: calendarInvitationLanguageSchema.optional(),
3528
3601
  description: noControlString(32768, "description").nullish(),
@@ -4094,6 +4167,10 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4094
4167
  var bridge = window.openai;
4095
4168
  var input = bridge && bridge.toolInput ? bridge.toolInput : {};
4096
4169
  var selectedFile = input.file || null;
4170
+ // Once the send tool has been called, its outcome can be ambiguous to
4171
+ // the card (for example, the host can lose the response after accepting
4172
+ // the request). Keep this exact payload until it resolves.
4173
+ var pendingSend = null;
4097
4174
  var submit = document.getElementById("submit");
4098
4175
  var change = document.getElementById("change");
4099
4176
  var status = document.getElementById("status");
@@ -4115,7 +4192,9 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4115
4192
  }
4116
4193
  function setBusy(busy) {
4117
4194
  submit.disabled = busy;
4118
- change.disabled = busy;
4195
+ // A different file would turn an uncertain, already-accepted request
4196
+ // into a new one. It stays unavailable until this request resolves.
4197
+ change.disabled = busy || Boolean(pendingSend);
4119
4198
  }
4120
4199
  function readUrl(value) {
4121
4200
  if (typeof value === "string") return value;
@@ -4149,8 +4228,12 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4149
4228
  if (bridge && typeof bridge.selectFiles === "function") {
4150
4229
  change.hidden = false;
4151
4230
  change.addEventListener("click", async function () {
4231
+ if (pendingSend) return;
4152
4232
  try {
4153
4233
  var files = await bridge.selectFiles();
4234
+ // The picker may have opened before a send crossed its boundary.
4235
+ // Do not let its late result replace the retained request.
4236
+ if (pendingSend) return;
4154
4237
  if (files && files[0]) {
4155
4238
  selectedFile = files[0];
4156
4239
  text("file", fileName(selectedFile));
@@ -4174,6 +4257,15 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4174
4257
 
4175
4258
  setBusy(true);
4176
4259
  try {
4260
+ if (pendingSend) {
4261
+ setStatus(input.scheduled_at ? "Checking the scheduled message..." : "Checking the message send...");
4262
+ var retried = await bridge.callTool("shipmail_send_message", pendingSend);
4263
+ if (hasToolError(retried)) throw new Error("send_failed");
4264
+ setStatus(input.scheduled_at ? "Message scheduled." : "Message sent.", "success");
4265
+ submit.hidden = true;
4266
+ change.hidden = true;
4267
+ return;
4268
+ }
4177
4269
  setStatus("Downloading the selected file...");
4178
4270
  var fileId = selectedFile.file_id || selectedFile.fileId;
4179
4271
  var downloadUrl = selectedFile.download_url || selectedFile.downloadUrl || null;
@@ -4231,13 +4323,22 @@ var ATTACHMENT_COMPOSER_HTML = String.raw`<!doctype html>
4231
4323
  idempotency_key: "mcp_app_" + crypto.randomUUID().replace(/-/g, "")
4232
4324
  });
4233
4325
  delete sendInput.file;
4234
- var sent = await bridge.callTool("shipmail_send_message", sendInput);
4326
+ pendingSend = sendInput;
4327
+ submit.textContent = input.scheduled_at ? "Check scheduled result" : "Check send result";
4328
+ var sent = await bridge.callTool("shipmail_send_message", pendingSend);
4235
4329
  if (hasToolError(sent)) throw new Error("send_failed");
4236
4330
  setStatus(input.scheduled_at ? "Message scheduled." : "Message sent.", "success");
4237
4331
  submit.hidden = true;
4238
4332
  change.hidden = true;
4239
4333
  } catch (error) {
4240
- setStatus("The attachment could not be sent. No automatic retry was made.", "error");
4334
+ setStatus(
4335
+ pendingSend
4336
+ ? input.scheduled_at
4337
+ ? "The scheduling result is unknown. Check Scheduled Messages before retrying; retry uses the same request."
4338
+ : "The send result is unknown. Check Sent before retrying; retry uses the same request."
4339
+ : "The attachment could not be prepared for sending.",
4340
+ "error"
4341
+ );
4241
4342
  } finally {
4242
4343
  setBusy(false);
4243
4344
  }
@@ -5226,6 +5327,20 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
5226
5327
  }))
5227
5328
  );
5228
5329
  });
5330
+ registerIfAllowed("shipmail_get_organization_access", () => {
5331
+ server.registerTool(
5332
+ "shipmail_get_organization_access",
5333
+ {
5334
+ title: "Get Organization Access",
5335
+ description: "Check whether the organization can create mailboxes now: plan, has_access, trial state and end, trial eligibility, mailbox limit and usage, and whether newsletters are allowed. Poll it after the owner opens the billing link: access appears once Shipmail has recorded the payment. Never choose or pay for a plan yourself.",
5336
+ outputSchema: organizationAccessOutputSchema,
5337
+ annotations: { readOnlyHint: true, openWorldHint: false }
5338
+ },
5339
+ async () => runTool("shipmail_get_organization_access", organizationAccessOutputSchema, async () => ({
5340
+ access: await client.organization.access()
5341
+ }))
5342
+ );
5343
+ });
5229
5344
  registerIfAllowed("shipmail_list_domains", () => {
5230
5345
  server.registerTool(
5231
5346
  "shipmail_list_domains",
@@ -5263,7 +5378,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
5263
5378
  "shipmail_get_domain_dns_records",
5264
5379
  {
5265
5380
  title: "Get Domain DNS Records",
5266
- description: "Return all six DNS records required by Shipmail and live observed values for propagation diagnostics. This does not update domain state.",
5381
+ description: "Return the DNS records Shipmail requires for this domain and live observed values for propagation diagnostics. A connected domain needs four: MX, SPF, DKIM and DMARC. A domain bought through Shipmail also lists two mail-subdomain records, which Shipmail adds itself. This does not update domain state.",
5267
5382
  inputSchema: getByIdInputSchema,
5268
5383
  outputSchema: domainDnsRecordsOutputSchema,
5269
5384
  annotations: { readOnlyHint: true, openWorldHint: true }
@@ -6443,7 +6558,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
6443
6558
  "shipmail_create_mailbox_forwarding",
6444
6559
  {
6445
6560
  title: "Add Mailbox Forwarding",
6446
- description: "Send a confirmation email to a forwarding destination. Delivery begins after recipient confirmation, keeps a local copy, and excludes spam.",
6561
+ description: "Send a confirmation email to a forwarding destination. Optionally filter by exact From address, delivery recipient, or both. Delivery begins after confirmation, keeps a local copy, and excludes spam.",
6447
6562
  inputSchema: createMailboxForwardingInputSchema,
6448
6563
  outputSchema: mailboxForwardingOutputSchema,
6449
6564
  annotations: {
@@ -6456,7 +6571,11 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
6456
6571
  async (args) => runTool("shipmail_create_mailbox_forwarding", mailboxForwardingOutputSchema, async () => ({
6457
6572
  forwarding: await client.mailboxes.createForwarding(
6458
6573
  args.id,
6459
- { destination: args.destination, sender: args.sender ?? null },
6574
+ {
6575
+ destination: args.destination,
6576
+ sender: args.sender ?? null,
6577
+ recipient: args.recipient ?? null
6578
+ },
6460
6579
  mutationOptions(args)
6461
6580
  )
6462
6581
  }))
@@ -6994,7 +7113,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
6994
7113
  "shipmail_list_members",
6995
7114
  {
6996
7115
  title: "List Members",
6997
- description: "List organization members.",
7116
+ description: "List organization members and their mailbox access. Selected mailbox IDs are limited to mailboxes visible to this API credential and may be partial.",
6998
7117
  inputSchema: listMembersInputSchema,
6999
7118
  outputSchema: membersOutputSchema,
7000
7119
  annotations: { readOnlyHint: true, openWorldHint: false }
@@ -7011,7 +7130,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7011
7130
  "shipmail_get_member",
7012
7131
  {
7013
7132
  title: "Get Member",
7014
- description: "Fetch an organization member by ID.",
7133
+ description: "Fetch an organization member and their mailbox access by ID. Selected mailbox IDs are limited to mailboxes visible to this API credential and may be partial.",
7015
7134
  inputSchema: getByIdInputSchema,
7016
7135
  outputSchema: memberOutputSchema,
7017
7136
  annotations: { readOnlyHint: true, openWorldHint: false }
@@ -7493,7 +7612,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7493
7612
  "shipmail_create_newsletter",
7494
7613
  {
7495
7614
  title: "Create Newsletter",
7496
- description: "Create a newsletter draft for an audience and sender identity. Shipmail renders blocks to email-safe HTML and text. Paragraph, quote, callout, list-item, and column bodies accept text or sanitized inline HTML. styled applies Shipmail's email theme. plain preserves HTML without injected styles, width, or centering.",
7615
+ description: "Create a newsletter draft for an audience and sender identity. Shipmail renders blocks to email-safe HTML and text. Paragraph, quote, callout, list-item, and column bodies accept text or sanitized inline HTML. styled applies Shipmail's email theme. plain preserves HTML without injected styles, width, or centering. track_engagement turns on open and click tracking for this issue; it is off by default.",
7497
7616
  inputSchema: createNewsletterInputSchema,
7498
7617
  outputSchema: newsletterOutputSchema,
7499
7618
  annotations: {
@@ -7539,7 +7658,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7539
7658
  "shipmail_update_newsletter",
7540
7659
  {
7541
7660
  title: "Update Newsletter",
7542
- description: "Update an editable newsletter draft or future scheduled newsletter. Paragraph, quote, callout, list-item, and column bodies accept text or sanitized inline HTML. body_text alone updates the plain-text override when blocks exist. Sending and sent newsletters cannot be edited. Concurrent saves return conflict (409). styled applies Shipmail's email theme. plain preserves HTML without injected styles, width, or centering.",
7661
+ description: "Update an editable newsletter draft or future scheduled newsletter. Changing message content, presentation, or audience returns a scheduled newsletter to draft and clears scheduled_at; inspect the returned status, send a new test, and schedule again. Name, feed link, and send-window changes can keep the schedule. Paragraph, quote, callout, list-item, and column bodies accept text or sanitized inline HTML. body_text alone updates the plain-text override when blocks exist. Sending and sent newsletters cannot be edited. Concurrent saves return conflict (409). styled applies Shipmail's email theme. plain preserves HTML without injected styles, width, or centering. track_engagement turns open and click tracking on or off for this issue.",
7543
7662
  inputSchema: updateNewsletterInputSchema,
7544
7663
  outputSchema: newsletterOutputSchema,
7545
7664
  annotations: {
@@ -7566,7 +7685,8 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
7566
7685
  ...rest.send_window_hours !== void 0 ? { send_window_hours: rest.send_window_hours } : {},
7567
7686
  ...rest.archive_visibility !== void 0 ? { archive_visibility: rest.archive_visibility } : {},
7568
7687
  ...rest.feed_entry_url !== void 0 ? { feed_entry_url: rest.feed_entry_url } : {},
7569
- ...rest.styling_mode !== void 0 ? { styling_mode: rest.styling_mode } : {}
7688
+ ...rest.styling_mode !== void 0 ? { styling_mode: rest.styling_mode } : {},
7689
+ ...rest.track_engagement !== void 0 ? { track_engagement: rest.track_engagement } : {}
7570
7690
  },
7571
7691
  mutationOptions(args)
7572
7692
  )
@@ -8096,9 +8216,9 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8096
8216
  "shipmail_create_calendar_event",
8097
8217
  {
8098
8218
  title: "Create Calendar Event",
8099
- description: "Create a calendar event on a mailbox's calendar. start is a local date-time; its zone is given by timezone.",
8219
+ description: "Create a calendar event on a mailbox's calendar. start is a local date-time; its zone is given by timezone. Reuse operation_key only when retrying the exact same payload.",
8100
8220
  inputSchema: createCalendarEventInputSchema,
8101
- outputSchema: calendarEventOutputSchema,
8221
+ outputSchema: calendarEventMutationOutputSchema,
8102
8222
  annotations: {
8103
8223
  readOnlyHint: false,
8104
8224
  destructiveHint: false,
@@ -8106,7 +8226,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8106
8226
  openWorldHint: false
8107
8227
  }
8108
8228
  },
8109
- async (args) => runTool("shipmail_create_calendar_event", calendarEventOutputSchema, async () => ({
8229
+ async (args) => runTool("shipmail_create_calendar_event", calendarEventMutationOutputSchema, async () => ({
8110
8230
  event: await client.calendar.events.create(
8111
8231
  stripIdempotencyKey(args),
8112
8232
  mutationOptions(args)
@@ -8119,9 +8239,9 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8119
8239
  "shipmail_update_calendar_event",
8120
8240
  {
8121
8241
  title: "Update Calendar Event",
8122
- description: "Update a calendar event. Omitted fields are unchanged; send null to clear description, timezone, location, video_url, recurrence, or reminders.",
8242
+ description: "Update a calendar event. Omitted fields are unchanged; send null to clear description, timezone, location, video_url, recurrence, or reminders. Use expected_revision from a prior read and reuse operation_key only for an exact-payload retry.",
8123
8243
  inputSchema: updateCalendarEventInputSchema,
8124
- outputSchema: calendarEventOutputSchema,
8244
+ outputSchema: calendarEventMutationOutputSchema,
8125
8245
  annotations: {
8126
8246
  readOnlyHint: false,
8127
8247
  destructiveHint: false,
@@ -8129,7 +8249,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8129
8249
  openWorldHint: false
8130
8250
  }
8131
8251
  },
8132
- async (args) => runTool("shipmail_update_calendar_event", calendarEventOutputSchema, async () => {
8252
+ async (args) => runTool("shipmail_update_calendar_event", calendarEventMutationOutputSchema, async () => {
8133
8253
  const { id, idempotency_key: _key, ...params } = args;
8134
8254
  return { event: await client.calendar.events.update(id, params, mutationOptions(args)) };
8135
8255
  })
@@ -8381,7 +8501,7 @@ function registerTools(rawServer, client, allowedTools, grantedOrganizations = [
8381
8501
  }
8382
8502
 
8383
8503
  // src/version.ts
8384
- var VERSION = "0.9.1";
8504
+ var VERSION = "0.9.3";
8385
8505
 
8386
8506
  // src/server.ts
8387
8507
  var SHIPMAIL_MCP_INSTRUCTIONS = `Shipmail MCP exposes the business email and calendar tools authorized by the connection's current Shipmail permissions.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Shipmail",
3
3
  "name": "shipmail",
4
- "version": "0.9.1",
4
+ "version": "0.9.3",
5
5
  "description": "Modern email for your business. Inboxes, calendars, newsletters, bookings, an AI assistant, and an API for your agents. Everything on your own domain, in one subscription.",
6
6
  "author": {
7
7
  "name": "Shipmail",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipmail",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Modern email for your business. Inboxes, calendars, newsletters, bookings, an AI assistant, and an API for your agents. Everything on your own domain, in one subscription.",
5
5
  "author": {
6
6
  "name": "Shipmail",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipmail",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Modern email for your business. Inboxes, calendars, newsletters, bookings, an AI assistant, and an API for your agents. Everything on your own domain, in one subscription.",
5
5
  "author": {
6
6
  "name": "Shipmail",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shipmail-mcp",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "mcpName": "io.github.shipmail-to/shipmail-mcp",
5
5
  "description": "Official Model Context Protocol (MCP) server for Shipmail, a business email provider with REST API, webhooks, and custom-domain inboxes for AI agents.",
6
6
  "type": "module",
@@ -68,7 +68,7 @@
68
68
  },
69
69
  "dependencies": {
70
70
  "@modelcontextprotocol/server": "2.0.0",
71
- "shipmail": "0.6.0",
71
+ "shipmail": "0.6.3",
72
72
  "zod": "4.4.3"
73
73
  },
74
74
  "devDependencies": {
package/server.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "url": "https://github.com/shipmail-to/shipmail-mcp",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.9.1",
9
+ "version": "0.9.3",
10
10
  "websiteUrl": "https://shipmail.to/docs/mcp",
11
11
  "remotes": [
12
12
  {
@@ -27,7 +27,7 @@
27
27
  "registryType": "npm",
28
28
  "registryBaseUrl": "https://registry.npmjs.org",
29
29
  "identifier": "shipmail-mcp",
30
- "version": "0.9.1",
30
+ "version": "0.9.3",
31
31
  "transport": {
32
32
  "type": "stdio"
33
33
  },
package/smithery.yaml CHANGED
@@ -1,6 +1,6 @@
1
1
  # Smithery configuration file: https://smithery.ai/docs/build/project-config/smithery-yaml
2
2
  name: shipmail-mcp
3
- version: 0.9.1
3
+ version: 0.9.3
4
4
  description: Official Shipmail MCP server for AI-agent custom-domain business email inboxes with REST API and webhooks.
5
5
  author: Shipmail
6
6
  repository: https://github.com/shipmail-to/shipmail-mcp