@sendora/mcp 1.8.16 → 1.9.0

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.
@@ -356,7 +356,7 @@ button:focus-visible {
356
356
  }
357
357
 
358
358
  // src/version.ts
359
- var MCP_VERSION = "1.8.16";
359
+ var MCP_VERSION = "1.9.0";
360
360
 
361
361
  // screens/host.ts
362
362
  var PROTOCOL_VERSION = "2026-01-26";
@@ -356,7 +356,7 @@ button:focus-visible {
356
356
  }
357
357
 
358
358
  // src/version.ts
359
- var MCP_VERSION = "1.8.16";
359
+ var MCP_VERSION = "1.9.0";
360
360
 
361
361
  // screens/host.ts
362
362
  var PROTOCOL_VERSION = "2026-01-26";
@@ -10,6 +10,7 @@ import { getServerTool } from './tools/server.js';
10
10
  import { deleteTestServerTool, listServersTool } from './tools/servers.js';
11
11
  import { archiveStreamTool, createStreamTool } from './tools/streams.js';
12
12
  import { listSuppressionsTool, removeSuppressionTool } from './tools/suppressions.js';
13
+ import { addTrackingDomainTool, checkTrackingDomainTool, listTrackingDomainsTool, } from './tools/tracking-domains.js';
13
14
  import { createWebhookTool, deleteWebhookTool, listWebhookDeliveriesTool, listWebhooksTool, replayWebhookDeliveryTool, } from './tools/webhooks.js';
14
15
  /**
15
16
  * Every tool the server has, with its class, its reach and the operations it
@@ -47,5 +48,8 @@ export const toolTable = [
47
48
  listDomainsTool,
48
49
  checkDomainTool,
49
50
  addDomainTool,
51
+ listTrackingDomainsTool,
52
+ checkTrackingDomainTool,
53
+ addTrackingDomainTool,
50
54
  deleteTestServerTool,
51
55
  ];
@@ -0,0 +1,155 @@
1
+ import { z } from 'zod';
2
+ import { toolError } from '../errors.js';
3
+ import { READING } from '../tool.js';
4
+ import { accountConnectionOf } from './servers.js';
5
+ const trackingDomainOutput = z.object({
6
+ trackingDomainId: z.string().describe('What check_tracking_domain checks it by.'),
7
+ host: z.string().describe('The host tracked links and the open pixel use.'),
8
+ sendingDomainId: z
9
+ .string()
10
+ .nullable()
11
+ .describe('The sending domain whose new mail will use the host; null once that domain is deleted.'),
12
+ state: z
13
+ .enum([
14
+ 'pending',
15
+ 'waiting_for_certificate',
16
+ 'ready',
17
+ 'failing',
18
+ 'stopped',
19
+ 'sending_domain_lost',
20
+ ])
21
+ .describe('pending: the records have not been right yet. waiting_for_certificate: the records are right. ready: new mail from the sending domain uses the host. failing: a check found the records wrong, and new mail keeps using a host that was ready until 24 hours after failingSince. stopped: those 24 hours have passed. sending_domain_lost: the sending domain is deleted or has lost its verification.'),
22
+ createdAt: z.string().describe('When it was added.'),
23
+ lastCheckedAt: z.string().nullable().describe('When the records were last looked up.'),
24
+ certificateReadyAt: z
25
+ .string()
26
+ .nullable()
27
+ .describe('When the certificate was proved to work; null before that.'),
28
+ failingSince: z
29
+ .string()
30
+ .nullable()
31
+ .describe('When a check first found the records wrong on a host whose records have been right.'),
32
+ expiresAt: z
33
+ .string()
34
+ .nullable()
35
+ .describe('When a host whose records have never been right goes; null once they have been.'),
36
+ cname: z
37
+ .object({
38
+ type: z.literal('CNAME').describe('The record type.'),
39
+ host: z.string().describe('The name to create the record under.'),
40
+ value: z.string().describe('The value the record must hold.'),
41
+ check: z
42
+ .enum(['ok', 'missing', 'mismatch', 'proxied', 'dns_error'])
43
+ .nullable()
44
+ .describe('What the last check found; null before the first. mismatch is a record that points elsewhere, an A record included. proxied is a proxy in front of the name, which must be switched off. dns_error is a resolver failure and changes nothing.'),
45
+ })
46
+ .describe('The CNAME record for the user to add.'),
47
+ caa: z
48
+ .object({
49
+ check: z
50
+ .enum(['ok', 'no_lets_encrypt', 'other_account', 'no_http_01', 'dns_error'])
51
+ .nullable()
52
+ .describe('What the last check of the CAA records on the host and its parents found; null before the first. dns_error is a resolver failure and changes nothing.'),
53
+ record: z
54
+ .object({
55
+ type: z.literal('CAA').describe('The record type.'),
56
+ host: z.string().describe('The name that holds the CAA records in the way.'),
57
+ value: z.string().describe('The record to add beside them.'),
58
+ })
59
+ .nullable()
60
+ .describe('What lets the certificate be issued; null unless the check found a problem.'),
61
+ })
62
+ .describe('Whether CAA records let Let’s Encrypt issue the certificate.'),
63
+ });
64
+ export const listTrackingDomainsTool = {
65
+ name: 'list_tracking_domains',
66
+ title: 'List the tracking domains',
67
+ class: 'read',
68
+ reach: 'account',
69
+ operations: ['GET /v1/tracking-domains'],
70
+ register: (server, { connection }) => server.registerTool('list_tracking_domains', {
71
+ title: 'List the tracking domains',
72
+ description: "Lists the account's tracking domains, the hosts that tracked links and the open pixel use, each with the CNAME record it needs, its state and what the last check found. check_tracking_domain looks them up now. Tracking is not open to accounts yet, so a host carries no mail until it is.",
73
+ inputSchema: z.object({}),
74
+ outputSchema: z.object({
75
+ trackingDomains: z
76
+ .array(trackingDomainOutput)
77
+ .describe('Every tracking domain of the account.'),
78
+ }),
79
+ annotations: READING,
80
+ }, async () => {
81
+ try {
82
+ const list = await accountConnectionOf(connection).account.trackingDomains.list();
83
+ return {
84
+ content: [{ type: 'text', text: JSON.stringify(list) }],
85
+ structuredContent: list,
86
+ };
87
+ }
88
+ catch (error) {
89
+ return toolError(error, connection);
90
+ }
91
+ }),
92
+ };
93
+ export const checkTrackingDomainTool = {
94
+ name: 'check_tracking_domain',
95
+ title: 'Check a tracking domain',
96
+ class: 'read',
97
+ reach: 'account',
98
+ operations: ['POST /v1/tracking-domains/{id}/verify'],
99
+ register: (server, { connection }) => server.registerTool('check_tracking_domain', {
100
+ title: 'Check a tracking domain',
101
+ description: "Looks up the CNAME and the CAA records of one of the account's tracking domains now and answers it as it stands. A record just added may take a while to be seen. A dns_error changes nothing. A check that finds the records of a host wrong after they have been right begins a 24-hour warning and mails the account's administrators, as Sendora's own checks do.",
102
+ inputSchema: z.object({
103
+ trackingDomainId: z
104
+ .uuid()
105
+ .describe('The tracking domain, from list_tracking_domains or add_tracking_domain.'),
106
+ }),
107
+ outputSchema: trackingDomainOutput,
108
+ annotations: { ...READING, openWorldHint: true },
109
+ }, async ({ trackingDomainId }) => {
110
+ try {
111
+ const domain = await accountConnectionOf(connection).account.trackingDomains.verify(trackingDomainId);
112
+ return {
113
+ content: [{ type: 'text', text: JSON.stringify(domain) }],
114
+ structuredContent: domain,
115
+ };
116
+ }
117
+ catch (error) {
118
+ return toolError(error, connection);
119
+ }
120
+ }),
121
+ };
122
+ export const addTrackingDomainTool = {
123
+ name: 'add_tracking_domain',
124
+ title: 'Add a tracking domain',
125
+ class: 'write',
126
+ reach: 'account',
127
+ operations: ['POST /v1/tracking-domains'],
128
+ register: (server, { connection }) => server.registerTool('add_tracking_domain', {
129
+ title: 'Add a tracking domain',
130
+ description: "Claims a host under one of the account's verified sending domains for tracked links and the open pixel, and answers the CNAME record for the user to add to the domain's DNS. check_tracking_domain then looks it up. A host whose records are not right within 7 days goes. Tracking is not open to accounts yet, so a host carries no mail until it is. This is for tracking only: add_domain adds the domain mail is sent from.",
131
+ inputSchema: z.object({
132
+ host: z
133
+ .string()
134
+ .describe('The host, such as links.example.se: a subdomain of a verified sending domain, never the domain itself.'),
135
+ }),
136
+ outputSchema: trackingDomainOutput,
137
+ annotations: {
138
+ readOnlyHint: false,
139
+ destructiveHint: false,
140
+ idempotentHint: false,
141
+ openWorldHint: false,
142
+ },
143
+ }, async (request) => {
144
+ try {
145
+ const domain = await accountConnectionOf(connection).account.trackingDomains.create(request);
146
+ return {
147
+ content: [{ type: 'text', text: JSON.stringify(domain) }],
148
+ structuredContent: domain,
149
+ };
150
+ }
151
+ catch (error) {
152
+ return toolError(error, connection);
153
+ }
154
+ }),
155
+ };
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** This package's version, held equal to its package.json by a test. */
2
- export const MCP_VERSION = '1.8.16';
2
+ export const MCP_VERSION = '1.9.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendora/mcp",
3
- "version": "1.8.16",
3
+ "version": "1.9.0",
4
4
  "description": "The official MCP server for Sendora: its documentation and API for coding agents.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -25,7 +25,7 @@
25
25
  "dependencies": {
26
26
  "@modelcontextprotocol/server": "^2.1.0",
27
27
  "zod": "^4.6.2",
28
- "@sendora/sdk": "^5.0.2"
28
+ "@sendora/sdk": "^5.1.0"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@anthropic-ai/mcpb": "2.1.2",