@sendinel/mcp-server 1.0.128 → 1.0.129
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 +2 -2
- package/build/tools/social-posts.js +20 -10
- package/build/tools/webhooks.js +15 -1
- package/package.json +1 -1
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 343 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
|
|-------|-------|---------|
|
|
@@ -56,7 +56,7 @@ Sendinel currently exposes 35 tool groups and 342 tools (gateway mode exposes 4
|
|
|
56
56
|
| `surveys` | 5 | Survey creation, listing, status, results |
|
|
57
57
|
| `templates` | 7 | Email template CRUD, version restore, migration translation |
|
|
58
58
|
| `warmup` | 4 | IP/domain warmup schedule control |
|
|
59
|
-
| `webhooks` |
|
|
59
|
+
| `webhooks` | 5 | Webhook subscription management |
|
|
60
60
|
|
|
61
61
|
## Install / run
|
|
62
62
|
|
|
@@ -5,7 +5,7 @@ import { db, adminDb } from '../db.js';
|
|
|
5
5
|
import { decrypt } from '../crypto.js';
|
|
6
6
|
import { getProjectId } from '../project.js';
|
|
7
7
|
import { getAnthropicModelId } from '../anthropic-model.js';
|
|
8
|
-
import { AI_MAX_TOKENS, outputConfig, anthropicCheckedText, assertProjectSandboxTargets } from '@sendinel/domain';
|
|
8
|
+
import { AI_MAX_TOKENS, outputConfig, anthropicCheckedText, recordSandboxSocialPost, configuredSandboxSocialProfile, assertProjectSandboxTargets } from '@sendinel/domain';
|
|
9
9
|
import { buildVoicePrompt } from '../lib/voice.js';
|
|
10
10
|
import { buildSocialSystemPrompt, buildSocialUserPrompt, parseSocialResponse, selectArchetype, } from '../lib/social-engine/index.js';
|
|
11
11
|
import { fireWebhookEvent } from '../lib/webhook-events.js';
|
|
@@ -40,6 +40,13 @@ function buildSocialTrackedUrl(params) {
|
|
|
40
40
|
};
|
|
41
41
|
}
|
|
42
42
|
async function scheduleUploadPost(apiKey, params) {
|
|
43
|
+
const mock = await recordSandboxSocialPost(adminDb(), {
|
|
44
|
+
projectId: params.projectId, profileId: params.profileId, platforms: [params.platform],
|
|
45
|
+
text: params.link ? `${params.content}\n\n${params.link}` : params.content,
|
|
46
|
+
mediaUrls: params.mediaUrls, scheduledAt: params.scheduledAt,
|
|
47
|
+
});
|
|
48
|
+
if (mock)
|
|
49
|
+
return mock;
|
|
43
50
|
await assertProjectSandboxTargets(adminDb(), params.projectId, 'social', params.profileId ? [`uploadpost:${params.platform}:${params.profileId}`] : []);
|
|
44
51
|
const res = await fetch(`${UPLOADPOST_API_BASE}/uploadposts/schedule`, {
|
|
45
52
|
method: 'POST',
|
|
@@ -713,26 +720,29 @@ export function registerSocialPostTools(server) {
|
|
|
713
720
|
return j({ error: 'Campaign not found', code: 'NOT_FOUND' });
|
|
714
721
|
const { data: project, error: projectError } = await admin
|
|
715
722
|
.from('projects')
|
|
716
|
-
.select('org_id')
|
|
723
|
+
.select('org_id, sandbox_mode, sandbox_allowed_social_profiles')
|
|
717
724
|
.eq('id', campaign.project_id)
|
|
718
725
|
.maybeSingle();
|
|
719
726
|
if (projectError)
|
|
720
727
|
return txt(`Error: ${projectError.message}`);
|
|
721
728
|
if (!project?.org_id)
|
|
722
729
|
return j({ error: 'Project not found', code: 'NOT_FOUND' });
|
|
723
|
-
const
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
730
|
+
const mockProfile = configuredSandboxSocialProfile(project, campaign.platform);
|
|
731
|
+
const { data: connection, error: connectionError } = mockProfile
|
|
732
|
+
? { data: { encrypted_access_token: null, account_id: mockProfile }, error: null }
|
|
733
|
+
: await admin
|
|
734
|
+
.from('social_platform_connections')
|
|
735
|
+
.select('encrypted_access_token, account_id')
|
|
736
|
+
.eq('org_id', project.org_id)
|
|
737
|
+
.eq('platform', p.publisher)
|
|
738
|
+
.maybeSingle();
|
|
729
739
|
if (connectionError)
|
|
730
740
|
return txt(`Error: ${connectionError.message}`);
|
|
731
|
-
if (!connection?.encrypted_access_token) {
|
|
741
|
+
if (!mockProfile && !connection?.encrypted_access_token) {
|
|
732
742
|
return j({ error: `No ${p.publisher} connection found. Connect it in Settings -> Integrations.`, code: 'NO_CONNECTION' });
|
|
733
743
|
}
|
|
734
744
|
try {
|
|
735
|
-
const result = await publishViaByoPublisher(p.publisher, decrypt(connection.encrypted_access_token), {
|
|
745
|
+
const result = await publishViaByoPublisher(p.publisher, mockProfile ? "" : decrypt(connection.encrypted_access_token), {
|
|
736
746
|
projectId,
|
|
737
747
|
profileId: connection.account_id ?? undefined,
|
|
738
748
|
content: p.content,
|
package/build/tools/webhooks.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { withApproval } from '../lib/action-approvals.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import {
|
|
3
|
+
import { listSandboxWebhookEvents } from '@sendinel/domain';
|
|
4
|
+
import { db, adminDb } from '../db.js';
|
|
4
5
|
import { getProjectId } from '../project.js';
|
|
5
6
|
import { validateWebhookUrl, generateWebhookSecret } from '../lib/webhook-events.js';
|
|
6
7
|
const txt = (text) => ({ content: [{ type: 'text', text }] });
|
|
@@ -25,6 +26,19 @@ const VALID_EVENTS = [
|
|
|
25
26
|
'asset_link.viewed',
|
|
26
27
|
];
|
|
27
28
|
export function registerWebhookTools(server) {
|
|
29
|
+
server.registerTool('list_sandbox_webhook_events', {
|
|
30
|
+
title: 'List Sandbox Webhook Events',
|
|
31
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
32
|
+
description: 'Read recent captured webhook requests for the active sandbox project (seven-day retention). Never returns sink tokens.',
|
|
33
|
+
inputSchema: { limit: z.number().int().min(1).max(100).optional().default(20) },
|
|
34
|
+
}, async ({ limit }) => {
|
|
35
|
+
try {
|
|
36
|
+
return j({ events: await listSandboxWebhookEvents(adminDb(), getProjectId(), limit) });
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return txt('Sandbox webhook events unavailable.');
|
|
40
|
+
}
|
|
41
|
+
});
|
|
28
42
|
server.registerTool('subscribe_webhook', {
|
|
29
43
|
title: 'Subscribe Webhook',
|
|
30
44
|
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.129",
|
|
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",
|