supersendtx-mcp 0.6.32 → 0.6.34
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 +7 -2
- package/dist/index.js +130 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -134,14 +134,19 @@ These call the app host and need a full-access key (OAuth sign-in and dashboard
|
|
|
134
134
|
|
|
135
135
|
| Tool | Purpose |
|
|
136
136
|
|------|---------|
|
|
137
|
-
| `arc_ensure_thread` / `arc_list_threads` | Durable thread for this client |
|
|
137
|
+
| `arc_ensure_thread` / `arc_list_threads` | Durable thread for this client; list threads a page at a time |
|
|
138
|
+
| `arc_get_thread` | Read a thread's messages, artifacts and waiting approvals |
|
|
138
139
|
| `arc_message` | Send text to Ranla and wait for the turn — returns `text`, `artifacts`, and `pendingApproval` |
|
|
139
140
|
| `arc_list_approvals` / `arc_approve` / `arc_reject` | Answer approvals |
|
|
140
141
|
| `arc_request_connection` | Connect link for a missing integration |
|
|
141
|
-
| `arc_<tool>` | Read-only Ranla tools, listed from the account with input schemas |
|
|
142
|
+
| `arc_<tool>` | Read-only Ranla tools, listed from the account with input schemas. Results say in `forCaller` when a step needs `arc_message` |
|
|
142
143
|
|
|
143
144
|
Flow: `arc_ensure_thread` → `arc_message` → if a step needs approval, `arc_list_approvals` → `arc_approve` or `arc_reject`.
|
|
144
145
|
|
|
146
|
+
An SEO page approval also carries `actionId`: pass it to `arc_seo_page_package` to read the draft, for example to build the page in your own repo.
|
|
147
|
+
|
|
148
|
+
Every tool has a `title` and `readOnlyHint` / `destructiveHint` annotations, so clients can run reads without asking and confirm writes.
|
|
149
|
+
|
|
145
150
|
Full reference: https://docs.supersendtx.com/ai/mcp
|
|
146
151
|
|
|
147
152
|
## License
|
package/dist/index.js
CHANGED
|
@@ -84,7 +84,63 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprot
|
|
|
84
84
|
import { SuperSendTX } from "supersendtx";
|
|
85
85
|
|
|
86
86
|
// package.json
|
|
87
|
-
var version = "0.6.
|
|
87
|
+
var version = "0.6.34";
|
|
88
|
+
|
|
89
|
+
// src/annotations.ts
|
|
90
|
+
var READ = { readOnlyHint: true };
|
|
91
|
+
var WRITE = { readOnlyHint: false, destructiveHint: false };
|
|
92
|
+
var DELETE = { readOnlyHint: false, destructiveHint: true };
|
|
93
|
+
var FIXED_TOOL_HINTS = {
|
|
94
|
+
send_email: { ...WRITE, openWorldHint: true },
|
|
95
|
+
list_emails: READ,
|
|
96
|
+
get_email: READ,
|
|
97
|
+
cancel_email: DELETE,
|
|
98
|
+
list_received_emails: READ,
|
|
99
|
+
get_received_email: READ,
|
|
100
|
+
list_domains: READ,
|
|
101
|
+
get_domain: READ,
|
|
102
|
+
create_domain: WRITE,
|
|
103
|
+
apply_domain_dns: { ...WRITE, title: "Apply domain DNS records", openWorldHint: true },
|
|
104
|
+
verify_domain: { ...WRITE, idempotentHint: true },
|
|
105
|
+
list_webhooks: READ,
|
|
106
|
+
create_webhook: WRITE,
|
|
107
|
+
delete_webhook: DELETE,
|
|
108
|
+
list_suppressions: READ,
|
|
109
|
+
add_suppression: { ...WRITE, idempotentHint: true },
|
|
110
|
+
remove_suppression: DELETE,
|
|
111
|
+
list_templates: READ,
|
|
112
|
+
get_template: READ,
|
|
113
|
+
create_template: WRITE,
|
|
114
|
+
publish_template: WRITE,
|
|
115
|
+
send_test_webhook_event: { ...WRITE, openWorldHint: true },
|
|
116
|
+
get_deliverability: READ,
|
|
117
|
+
arc_list_threads: { ...READ, title: "List Ranla threads" },
|
|
118
|
+
arc_get_thread: { ...READ, title: "Read a Ranla thread" },
|
|
119
|
+
arc_ensure_thread: { ...WRITE, title: "Open a Ranla thread", idempotentHint: true },
|
|
120
|
+
arc_message: { ...WRITE, title: "Message Ranla" },
|
|
121
|
+
arc_list_approvals: { ...READ, title: "List pending approvals" },
|
|
122
|
+
/** Approving can send email to real people. */
|
|
123
|
+
arc_approve: { ...WRITE, title: "Approve a Ranla step", openWorldHint: true },
|
|
124
|
+
/** Rejecting discards the proposal. */
|
|
125
|
+
arc_reject: { ...DELETE, title: "Reject a Ranla step" }
|
|
126
|
+
};
|
|
127
|
+
var UPPER = /* @__PURE__ */ new Set(["ai", "aeo", "api", "dns", "id", "seo", "url"]);
|
|
128
|
+
function titleFromToolName(name) {
|
|
129
|
+
const words = name.replace(/^arc_/, "").split("_").filter(Boolean);
|
|
130
|
+
return words.map((word, index) => {
|
|
131
|
+
if (UPPER.has(word)) return word.toUpperCase();
|
|
132
|
+
return index === 0 ? word.charAt(0).toUpperCase() + word.slice(1) : word;
|
|
133
|
+
}).join(" ");
|
|
134
|
+
}
|
|
135
|
+
function mcpToolAnnotations(tool) {
|
|
136
|
+
const fixed = FIXED_TOOL_HINTS[tool.name];
|
|
137
|
+
if (fixed) {
|
|
138
|
+
const { title: title2, ...hints } = fixed;
|
|
139
|
+
return { title: title2 ?? titleFromToolName(tool.name), ...hints };
|
|
140
|
+
}
|
|
141
|
+
const title = titleFromToolName(tool.name);
|
|
142
|
+
return tool.readOnly === true ? { title, ...READ } : { title, ...WRITE };
|
|
143
|
+
}
|
|
88
144
|
|
|
89
145
|
// src/arc-talk-tools.ts
|
|
90
146
|
var ARC_MCP_TALK_GROWTH_TOOL_NAMES = [
|
|
@@ -96,6 +152,10 @@ var ARC_MCP_TALK_GROWTH_TOOL_NAMES = [
|
|
|
96
152
|
// A canvas document Ranla wrote, as it stands now. Writing to one mutates
|
|
97
153
|
// and goes through `arc_message` like every other write.
|
|
98
154
|
"read_canvas",
|
|
155
|
+
// The ids read_canvas takes; nothing else an external agent can call returns them.
|
|
156
|
+
"list_documents",
|
|
157
|
+
// Every image in the account, with public URLs an external agent can use as they are.
|
|
158
|
+
"list_library_images",
|
|
99
159
|
"get_setup_status",
|
|
100
160
|
"get_growth_health",
|
|
101
161
|
"get_revenue_health",
|
|
@@ -107,6 +167,7 @@ var ARC_MCP_TALK_GROWTH_TOOL_NAMES = [
|
|
|
107
167
|
"list_goals",
|
|
108
168
|
"list_lists",
|
|
109
169
|
"list_segments",
|
|
170
|
+
"get_segment",
|
|
110
171
|
"get_tracking_snippet",
|
|
111
172
|
"verify_tracking_install",
|
|
112
173
|
"list_automations",
|
|
@@ -134,7 +195,6 @@ var ARC_MCP_TALK_GROWTH_TOOL_NAMES = [
|
|
|
134
195
|
"get_ad_delivery_diagnostics",
|
|
135
196
|
"get_search_term_evidence",
|
|
136
197
|
"list_proposed_ad_campaigns",
|
|
137
|
-
"recommend_ad_landings",
|
|
138
198
|
"read_campaign_design",
|
|
139
199
|
"list_campaign_replies",
|
|
140
200
|
"get_learnings",
|
|
@@ -194,7 +254,8 @@ var TALK_READ_TOOLS = ARC_MCP_TALK_GROWTH_TOOL_NAMES.map((growthTool) => ({
|
|
|
194
254
|
description: `Read-only Ranla tool: ${growthTool.replace(/_/g, " ")}.`,
|
|
195
255
|
inputSchema: openObjectSchema("Pass the tool arguments as fields."),
|
|
196
256
|
kind: "growth",
|
|
197
|
-
growthTool
|
|
257
|
+
growthTool,
|
|
258
|
+
readOnly: true
|
|
198
259
|
}));
|
|
199
260
|
var SETUP_TOOLS = [
|
|
200
261
|
{
|
|
@@ -209,14 +270,40 @@ var SETUP_TOOLS = [
|
|
|
209
270
|
required: ["slot"]
|
|
210
271
|
},
|
|
211
272
|
kind: "growth",
|
|
212
|
-
growthTool: "request_connection"
|
|
273
|
+
growthTool: "request_connection",
|
|
274
|
+
readOnly: false
|
|
213
275
|
}
|
|
214
276
|
];
|
|
215
277
|
var META_TOOLS = [
|
|
216
278
|
{
|
|
217
279
|
name: "arc_list_threads",
|
|
218
|
-
description: "List Ranla chat threads for this account.",
|
|
219
|
-
inputSchema:
|
|
280
|
+
description: "List Ranla chat threads for this account, most recent first: id, title, desk, last activity and a one-line preview. Pass nextBefore as before for older threads. Read one with arc_get_thread.",
|
|
281
|
+
inputSchema: {
|
|
282
|
+
type: "object",
|
|
283
|
+
properties: {
|
|
284
|
+
limit: { type: "integer", description: "Threads per page. Default 50, max 100." },
|
|
285
|
+
before: {
|
|
286
|
+
type: "string",
|
|
287
|
+
description: "ISO timestamp from nextBefore: only threads last active before it."
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
kind: "meta"
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
name: "arc_get_thread",
|
|
295
|
+
description: "Read a Ranla thread: its messages (role, text, tools used, artifacts by id, approvals waiting on arc_approve), newest page first. Pass earlierBefore as before for older messages.",
|
|
296
|
+
inputSchema: {
|
|
297
|
+
type: "object",
|
|
298
|
+
properties: {
|
|
299
|
+
threadId: { type: "string", description: "From arc_list_threads or arc_ensure_thread." },
|
|
300
|
+
before: {
|
|
301
|
+
type: "string",
|
|
302
|
+
description: "ISO timestamp from earlierBefore: the page of messages older than it."
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
required: ["threadId"]
|
|
306
|
+
},
|
|
220
307
|
kind: "meta"
|
|
221
308
|
},
|
|
222
309
|
{
|
|
@@ -246,7 +333,7 @@ var META_TOOLS = [
|
|
|
246
333
|
},
|
|
247
334
|
{
|
|
248
335
|
name: "arc_list_approvals",
|
|
249
|
-
description: "List pending Ranla
|
|
336
|
+
description: "List pending Ranla approvals across threads.",
|
|
250
337
|
inputSchema: openObjectSchema(),
|
|
251
338
|
kind: "meta"
|
|
252
339
|
},
|
|
@@ -334,7 +421,9 @@ async function loadArcMcpTools(apiKey, baseUrl) {
|
|
|
334
421
|
description: `${entry.mutates ? RANLA_AGENT_NAME : `${RANLA_AGENT_NAME}, read-only`}: ${entry.description}`,
|
|
335
422
|
inputSchema: entry.inputSchema,
|
|
336
423
|
kind: "growth",
|
|
337
|
-
growthTool: entry.name
|
|
424
|
+
growthTool: entry.name,
|
|
425
|
+
// Missing `mutates` is not a promise of read-only: only an explicit false is.
|
|
426
|
+
readOnly: entry.mutates === false
|
|
338
427
|
}))
|
|
339
428
|
];
|
|
340
429
|
}
|
|
@@ -361,7 +450,13 @@ async function callArcMcpTool(apiKey, name, args, baseUrl) {
|
|
|
361
450
|
}
|
|
362
451
|
switch (name) {
|
|
363
452
|
case "arc_list_threads": {
|
|
364
|
-
const
|
|
453
|
+
const query = new URLSearchParams();
|
|
454
|
+
const limit = optString(args, "limit");
|
|
455
|
+
const before = optString(args, "before");
|
|
456
|
+
if (limit) query.set("limit", limit);
|
|
457
|
+
if (before) query.set("before", before);
|
|
458
|
+
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
459
|
+
const response = await arcFetch(origin, apiKey, `/api/growth/threads${suffix}`);
|
|
365
460
|
if (!response.ok) {
|
|
366
461
|
throw new Error(
|
|
367
462
|
typeof response.body.error === "string" ? response.body.error : `List threads failed (${response.status})`
|
|
@@ -369,6 +464,22 @@ async function callArcMcpTool(apiKey, name, args, baseUrl) {
|
|
|
369
464
|
}
|
|
370
465
|
return response.body;
|
|
371
466
|
}
|
|
467
|
+
case "arc_get_thread": {
|
|
468
|
+
const threadId = optString(args, "threadId");
|
|
469
|
+
if (!threadId) throw new Error("Missing required argument: threadId");
|
|
470
|
+
const before = optString(args, "before");
|
|
471
|
+
const response = await arcFetch(
|
|
472
|
+
origin,
|
|
473
|
+
apiKey,
|
|
474
|
+
`/api/growth/threads/${encodeURIComponent(threadId)}${before ? `?before=${encodeURIComponent(before)}` : ""}`
|
|
475
|
+
);
|
|
476
|
+
if (!response.ok) {
|
|
477
|
+
throw new Error(
|
|
478
|
+
typeof response.body.error === "string" ? response.body.error : `Get thread failed (${response.status})`
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
return response.body;
|
|
482
|
+
}
|
|
372
483
|
case "arc_ensure_thread": {
|
|
373
484
|
const existingId = optString(args, "threadId");
|
|
374
485
|
if (existingId) {
|
|
@@ -1135,11 +1246,16 @@ function createMcpServer(apiKey, baseUrl) {
|
|
|
1135
1246
|
{ capabilities: { tools: {} } }
|
|
1136
1247
|
);
|
|
1137
1248
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
1138
|
-
tools: [...MCP_TOOLS, ...await loadArcMcpTools(apiKey, baseUrl)].map((tool) =>
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1249
|
+
tools: [...MCP_TOOLS, ...await loadArcMcpTools(apiKey, baseUrl)].map((tool) => {
|
|
1250
|
+
const annotations = mcpToolAnnotations(tool);
|
|
1251
|
+
return {
|
|
1252
|
+
name: tool.name,
|
|
1253
|
+
title: annotations.title,
|
|
1254
|
+
description: tool.description,
|
|
1255
|
+
inputSchema: tool.inputSchema,
|
|
1256
|
+
annotations
|
|
1257
|
+
};
|
|
1258
|
+
})
|
|
1143
1259
|
}));
|
|
1144
1260
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
1145
1261
|
const result = await callMcpTool(client, request.params.name, request.params.arguments ?? {}, {
|