@sendinel/mcp-server 1.0.93 → 1.0.95
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 +3 -3
- package/build/lib/action-approvals.js +1 -0
- package/build/lib/approval-exempt.js +1 -0
- package/build/server.js +2 -2
- package/build/tools/brand-kit.js +9 -0
- package/build/tools/contacts.js +20 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ AI-controlled email operations control plane for campaigns, contacts, segments,
|
|
|
12
12
|
|
|
13
13
|
## Tool groups
|
|
14
14
|
|
|
15
|
-
Sendinel currently exposes 35 tool groups and
|
|
15
|
+
Sendinel currently exposes 35 tool groups and 339 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.
|
|
16
16
|
|
|
17
17
|
| Group | Count | Purpose |
|
|
18
18
|
|-------|-------|---------|
|
|
@@ -23,12 +23,12 @@ Sendinel currently exposes 35 tool groups and 337 tools (gateway mode exposes 4
|
|
|
23
23
|
| `analytics` | 15 | Stats, portfolio analytics, project switching, domain health, engagement, deliverability, revenue analytics |
|
|
24
24
|
| `approvals` | 2 | Poll and list risk-tiered action approvals |
|
|
25
25
|
| `automations` | 7 | Automation triggers, previews, and response-gated escalation ladders |
|
|
26
|
-
| `brand_kit` |
|
|
26
|
+
| `brand_kit` | 6 | Brand Core text import, media library upload/URL ingest, asset-context reads, project logo selection |
|
|
27
27
|
| `campaigns` | 43 | Full campaign lifecycle: create, edit, approve, launch, enroll, schedule, sequence templates, convert imported campaigns |
|
|
28
28
|
| `cloud-import` | 6 | Cloud storage import |
|
|
29
29
|
| `compound` | 4 | Higher-level campaign/template/site setup and delivery diagnosis workflows |
|
|
30
30
|
| `connector` | 6 | BYOD connector status, table discovery, schema/view setup, mapping, resync |
|
|
31
|
-
| `contacts` |
|
|
31
|
+
| `contacts` | 38 | Subscriber CRUD, saved views, tags, email log, suppression, merge, timeline |
|
|
32
32
|
| `content` | 14 | Content blocks, gated asset links, blog ingest and auto-publish, sources |
|
|
33
33
|
| `data` | 19 | Platform connectors, imports, API keys, migration jobs, notifications, tenant export |
|
|
34
34
|
| `data-proposals` | 3 | Data-derived campaign proposal generation, listing, approval |
|
|
@@ -53,6 +53,7 @@ const GATED_ACTIONS = new Set([
|
|
|
53
53
|
'revoke_api_key', // breaks every integration using the key
|
|
54
54
|
'tenant_export_full', // copies all customer data out of Sendinel
|
|
55
55
|
'enroll_contact', // starts real emails to a contact
|
|
56
|
+
'identify_subscriber', // may enroll a new signup in sending campaigns
|
|
56
57
|
'enroll_automation', // starts automated messages to a contact
|
|
57
58
|
'enroll_in_escalation_ladder', // starts email/SMS escalation to a contact
|
|
58
59
|
'set_contact_sms_consent', // changes the consent record that allows texting
|
|
@@ -100,6 +100,7 @@ export const APPROVAL_EXEMPT = {
|
|
|
100
100
|
run_list_hygiene: "suppresses invalid or bouncing addresses, which only reduces who receives mail",
|
|
101
101
|
run_portfolio_analysis: "writes an internal analysis report only",
|
|
102
102
|
set_active_project: "switches which project this connection targets; no data written",
|
|
103
|
+
set_brand_logo: "copies an approved image to email storage and updates reversible project branding; sends nothing",
|
|
103
104
|
set_campaign_goal: "sets a goal definition on a campaign; sends nothing",
|
|
104
105
|
set_subscriber_tags: "edits tags on one contact; tag triggers go through enrollment rules the owner configured. FOLLOW-UP: confirm tag-triggered automations are covered",
|
|
105
106
|
set_white_label_settings: "edits branding settings; reversible and sends nothing",
|
package/build/server.js
CHANGED
|
@@ -82,7 +82,7 @@ export const ALL_TOOL_GROUPS = Object.keys(GROUP_REGISTRY);
|
|
|
82
82
|
const WRITE_TOOLS = new Set([
|
|
83
83
|
'recheck_domain_dns',
|
|
84
84
|
'mark_agent_message', 'draft_agent_reply', 'create_agent_mailbox',
|
|
85
|
-
'add_subscriber', 'import_subscribers', 'update_subscriber', 'bulk_update_subscribers',
|
|
85
|
+
'add_subscriber', 'identify_subscriber', 'import_subscribers', 'update_subscriber', 'bulk_update_subscribers',
|
|
86
86
|
'create_subscriber_view', 'update_subscriber_view', 'delete_subscriber_view',
|
|
87
87
|
'enrich_subscriber',
|
|
88
88
|
'create_campaign', 'update_campaign', 'delete_campaign', 'add_campaign_step', 'update_campaign_status',
|
|
@@ -135,7 +135,7 @@ const WRITE_TOOLS = new Set([
|
|
|
135
135
|
'create_signature', 'update_signature',
|
|
136
136
|
'mark_ai_work_item_seen', 'snooze_ai_work_item', 'dismiss_ai_work_item',
|
|
137
137
|
'submit_ai_context_event',
|
|
138
|
-
'import_brand_kit_text', 'rehost_brand_asset', 'ingest_brand_assets_by_url', 'upload_brand_asset',
|
|
138
|
+
'import_brand_kit_text', 'rehost_brand_asset', 'set_brand_logo', 'ingest_brand_assets_by_url', 'upload_brand_asset',
|
|
139
139
|
'create_newsletter', 'update_newsletter', 'create_newsletter_issue', 'schedule_newsletter_issue',
|
|
140
140
|
'send_newsletter_issue', 'subscribe_to_newsletter', 'unsubscribe_from_newsletter',
|
|
141
141
|
'retry_send_queue_rows', 'cancel_send_queue_rows',
|
package/build/tools/brand-kit.js
CHANGED
|
@@ -63,6 +63,15 @@ export function registerBrandKitTools(server) {
|
|
|
63
63
|
const result = await callBrandKitApi(`/api/v1/brand-kit/assets/${asset_id}/rehost`, { purpose, platforms });
|
|
64
64
|
return result.ok ? j(result.data) : j({ error: result.error });
|
|
65
65
|
});
|
|
66
|
+
server.registerTool('set_brand_logo', {
|
|
67
|
+
title: 'Set Project Brand Logo',
|
|
68
|
+
description: 'Use a confirmed PNG, JPEG, GIF or WebP brand asset as this project\'s email logo. Copies it to stable public email storage, preserves other brand settings, and reports site logo overrides without changing them.',
|
|
69
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
70
|
+
inputSchema: { asset_id: z.string().uuid() },
|
|
71
|
+
}, async ({ asset_id }) => {
|
|
72
|
+
const result = await callBrandKitApi(`/api/v1/brand-kit/assets/${asset_id}/use-as-logo`, {});
|
|
73
|
+
return result.ok ? j(result.data) : { ...j({ error: result.error }), isError: true };
|
|
74
|
+
});
|
|
66
75
|
server.registerTool('list_brand_assets', {
|
|
67
76
|
title: 'List Brand Assets',
|
|
68
77
|
annotations: {
|
package/build/tools/contacts.js
CHANGED
|
@@ -3,6 +3,7 @@ import { CONTACT_ENRICHMENT_PROVIDERS } from '@desler/models';
|
|
|
3
3
|
import { createContactEnrichmentAdapters, enrichContactFromConnections, } from '@desler/models/contact-enrichment';
|
|
4
4
|
import { buildPreviewAttentionEnvelope, applySegmentRules, ContactPropertyAnomalyLogger, normalizeContactProperties, getAttentionDecision, getContactNeighborhood, getScheduledTouches, findContactDuplicateGroups, readAllPages, readAllRows, chunkIds, } from '@sendinel/domain';
|
|
5
5
|
import { z } from 'zod';
|
|
6
|
+
import { callSendinelV1 } from '../lib/v1-client.js';
|
|
6
7
|
import { db, projectClientForWriteback } from '../db.js';
|
|
7
8
|
import { getProjectId } from '../project.js';
|
|
8
9
|
import { checkPlanLimit } from '../plan-limits.js';
|
|
@@ -535,6 +536,25 @@ async function exportSubscriberData(projectId, contactId) {
|
|
|
535
536
|
};
|
|
536
537
|
}
|
|
537
538
|
export function registerContactTools(server) {
|
|
539
|
+
server.registerTool('identify_subscriber', {
|
|
540
|
+
title: 'Identify Subscriber',
|
|
541
|
+
description: 'Identify or update a contact through the v1 identify API. Optional signup/customer consent subscribes new or existing contacts without overriding opt-outs. Customer consent requires a topic; consent requires site_id. Without consent, site_id retains legacy create-only subscription behavior and returns a warning.',
|
|
542
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
|
|
543
|
+
inputSchema: {
|
|
544
|
+
approval_id: z.string().uuid().optional().describe('Call once to request approval, then repeat the same arguments with the approved approval_id.'),
|
|
545
|
+
email: z.string().email(),
|
|
546
|
+
first_name: z.string().optional(),
|
|
547
|
+
last_name: z.string().optional(),
|
|
548
|
+
properties: z.record(z.string(), z.unknown()).optional(),
|
|
549
|
+
tags: z.array(z.string()).optional(),
|
|
550
|
+
site_id: z.string().uuid().optional(),
|
|
551
|
+
consent: z.enum(['signup', 'customer']).optional(),
|
|
552
|
+
topic: z.string().regex(/^[a-z0-9_]{1,64}$/).optional(),
|
|
553
|
+
},
|
|
554
|
+
}, withApproval('identify_subscriber', async (params) => {
|
|
555
|
+
const result = await callSendinelV1('/api/v1/identify', { method: 'POST', body: params });
|
|
556
|
+
return result.ok ? j(result.data) : err(JSON.stringify(result.error));
|
|
557
|
+
}));
|
|
538
558
|
server.registerTool('get_subscriber_timeline', {
|
|
539
559
|
title: 'Get Subscriber Timeline',
|
|
540
560
|
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.95",
|
|
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",
|