@sendinel/mcp-server 1.0.158 → 1.0.159
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.
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ preserves REST outcomes, and redacts failures. See the
|
|
|
18
18
|
[event-triggered campaign guide](../../docs/event-triggered-campaigns.md) for
|
|
19
19
|
inputs, idempotency, subscription requirements, and conditional step examples.
|
|
20
20
|
|
|
21
|
-
Sendinel currently exposes 35 tool groups and
|
|
21
|
+
Sendinel currently exposes 35 tool groups and 348 tools (gateway mode exposes 4 meta-tools, sharing how_to with full mode). These counts are checked against the tool registry in CI, so this table matches what ships.
|
|
22
22
|
|
|
23
23
|
| Group | Count | Purpose |
|
|
24
24
|
|-------|-------|---------|
|
|
@@ -49,7 +49,7 @@ Sendinel currently exposes 35 tool groups and 346 tools (gateway mode exposes 4
|
|
|
49
49
|
| `segments` | 6 | Audience builder: create, edit, natural-language generation, preview |
|
|
50
50
|
| `short-links` | 3 | Short links, click stats, QR codes |
|
|
51
51
|
| `signatures` | 4 | Sending signature blocks |
|
|
52
|
-
| `sites` |
|
|
52
|
+
| `sites` | 7 | Site, sender, and brand voice management |
|
|
53
53
|
| `skills` | 3 | Operator skills catalog |
|
|
54
54
|
| `sms` | 7 | SMS send, log, consent, inbound |
|
|
55
55
|
| `social-posts` | 17 | Social campaign creation, publisher scheduling, social posts, engagement reads, and LinkedIn reply proposals for human review |
|
|
@@ -175,6 +175,7 @@ export function buildApprovalSummary(action, params, display = {}) {
|
|
|
175
175
|
install_connector_view: (p) => `Reinstall the customer-side contact view for project ${p.project_id ?? 'current'}`,
|
|
176
176
|
set_connector_mapping: () => `Rewrite the BYOD connector field mapping`,
|
|
177
177
|
resync_connector: () => `Force a full BYOD connector resync`,
|
|
178
|
+
set_link_domain: (p) => `Set email link domain ${p.link_domain} for site ${p.site_id}${p.publish_dns ? ' and publish all DNS records through Cloudflare' : ''}`,
|
|
178
179
|
publish_dmarc_record: (p) => `Publish DMARC record for ${p.domain} - writes DNS in a customer-owned Cloudflare zone`,
|
|
179
180
|
broadcast_to_segment: (p) => broadcastSummary(display) ?? `Broadcast "${p.name || p.subject || 'untitled'}" to segment ${p.segment_id} — will send emails to real contacts`,
|
|
180
181
|
send_broadcast: (p) => {
|
|
@@ -14,6 +14,7 @@ export const APPROVAL_EXEMPT = {
|
|
|
14
14
|
mark_agent_message: "changes only the bound mailbox message status; reversible and sends nothing",
|
|
15
15
|
abuse_monitor_override: "admin-only override of Sendinel abuse monitoring on the caller own project; no outward send",
|
|
16
16
|
add_blackout_date: "adds a no-send date; reduces sending",
|
|
17
|
+
check_link_domain: "records the link-domain status after checking DNS, ownership and the certificate; links switch on only after Vercel and a TLS handshake both prove it, and sends nothing itself",
|
|
17
18
|
add_campaign_branch: "adds branching config to a campaign; recreatable and sends nothing itself",
|
|
18
19
|
add_campaign_step: "adds an email to a campaign; sends only when the campaign is activated (gated)",
|
|
19
20
|
add_subscriber: "adds one contact; contact count limits apply and nothing is sent",
|
package/build/server.js
CHANGED
|
@@ -105,7 +105,7 @@ const WRITE_TOOLS = new Set([
|
|
|
105
105
|
'create_social_post', 'update_social_post', 'delete_social_post',
|
|
106
106
|
'draft_social_reply', 'propose_social_reply', 'comment_on_post', 'reply_to_comment', 'request_social_reply',
|
|
107
107
|
'create_draft', 'approve_draft', 'reject_draft',
|
|
108
|
-
'create_site', 'create_sender', 'update_site',
|
|
108
|
+
'create_site', 'create_sender', 'update_site', 'set_link_domain', 'check_link_domain',
|
|
109
109
|
'create_template', 'update_template', 'delete_template', 'restore_template_version', 'delete_provider_credential', 'translate_template',
|
|
110
110
|
'delete_subscriber_data', 'identify_inactive', 'set_subscriber_tags',
|
|
111
111
|
'update_hygiene_config',
|
package/build/tools/sites.js
CHANGED
|
@@ -4,6 +4,8 @@ import { logAudit } from '../audit.js';
|
|
|
4
4
|
import { db } from '../db.js';
|
|
5
5
|
import { getProjectId } from '../project.js';
|
|
6
6
|
import { checkPlanLimit } from '../plan-limits.js';
|
|
7
|
+
import { withApproval } from '../lib/action-approvals.js';
|
|
8
|
+
import { callSendinelV1 } from '../lib/v1-client.js';
|
|
7
9
|
import { dbToolError } from '../lib/db-error.js';
|
|
8
10
|
const txt = (text) => ({ content: [{ type: 'text', text }] });
|
|
9
11
|
const j = (data) => txt(JSON.stringify(data, null, 2));
|
|
@@ -107,6 +109,29 @@ async function createSender({ name, slug, domain_id, local_part, sending_domain,
|
|
|
107
109
|
return j(data);
|
|
108
110
|
}
|
|
109
111
|
export function registerSiteTools(server) {
|
|
112
|
+
server.registerTool('set_link_domain', {
|
|
113
|
+
title: 'Set Link Domain',
|
|
114
|
+
description: 'Set a branded address for this site’s email links, such as links.example.com. Returns every DNS record, your DNS provider, setup steps and a plain status. Optionally publish all records through your connected Cloudflare account. One approval covers setup and optional DNS publishing.',
|
|
115
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
116
|
+
inputSchema: {
|
|
117
|
+
site_id: z.string().uuid(),
|
|
118
|
+
link_domain: z.string().min(1).describe('A subdomain for email links, such as links.example.com.'),
|
|
119
|
+
publish_dns: z.boolean().optional().describe('Publish the full record set using your connected Cloudflare account.'),
|
|
120
|
+
approval_id: z.string().uuid().optional().describe('Approval for this exact setup, including publish_dns.'),
|
|
121
|
+
},
|
|
122
|
+
}, withApproval('set_link_domain', async (args) => {
|
|
123
|
+
const result = await callSendinelV1('/api/v1/link-domain', { method: 'POST', body: args });
|
|
124
|
+
return result.ok ? j(result.data) : { ...j(result.error), isError: true };
|
|
125
|
+
}));
|
|
126
|
+
server.registerTool('check_link_domain', {
|
|
127
|
+
title: 'Check Link Domain',
|
|
128
|
+
description: 'Check whether this site’s branded email links are live. Returns every DNS record, your DNS provider, setup steps and a plain status. Checks DNS, ownership and the secure connection before enabling links.',
|
|
129
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
130
|
+
inputSchema: { site_id: z.string().uuid() },
|
|
131
|
+
}, async ({ site_id }) => {
|
|
132
|
+
const result = await callSendinelV1('/api/v1/link-domain', { method: 'GET', query: { site_id } });
|
|
133
|
+
return result.ok ? j(result.data) : { ...j(result.error), isError: true };
|
|
134
|
+
});
|
|
110
135
|
server.registerTool('get_brand_voice', {
|
|
111
136
|
title: 'Get Brand Voice',
|
|
112
137
|
annotations: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendinel/mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.159",
|
|
4
4
|
"description": "AI-controlled email operations control plane for campaigns, contacts, segments, analytics, and multi-provider sending via MCP.",
|
|
5
5
|
"mcpName": "ai.sendinel/mcp-server",
|
|
6
6
|
"type": "module",
|