@sendinel/mcp-server 1.0.217 → 1.0.219
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/build/lib/db-error.d.ts +5 -1
- package/build/lib/db-error.js +33 -6
- package/build/tools/campaigns.js +1 -1
- package/package.json +1 -1
package/build/lib/db-error.d.ts
CHANGED
|
@@ -63,10 +63,14 @@ export declare function formatZodError(error: z.ZodError | {
|
|
|
63
63
|
[key: string]: any;
|
|
64
64
|
}>;
|
|
65
65
|
}): string;
|
|
66
|
-
/** Machine-code classification
|
|
66
|
+
/** Machine-code classification shared by tool results and api_usage. Never rewrite legacy codes.
|
|
67
67
|
* Keys are case-insensitive; every supported legacy spelling is listed explicitly.
|
|
68
68
|
* Existing usage-only policy classes remain supported alongside the six tool classes. */
|
|
69
69
|
export declare const API_USAGE_ERROR_CODE_MAP: Readonly<Record<string, string>>;
|
|
70
|
+
/** One classifier for the additive response class and hosted usage tracking. */
|
|
71
|
+
export declare function classifyMachineCode(code: string): string | null;
|
|
72
|
+
/** Classify a failed body, preserving any explicitly supplied error_code. */
|
|
73
|
+
export declare function toolErrorClass(body: Record<string, unknown>): unknown;
|
|
70
74
|
type ToolResult = {
|
|
71
75
|
content: Array<{
|
|
72
76
|
type: string;
|
package/build/lib/db-error.js
CHANGED
|
@@ -99,7 +99,7 @@ export function formatZodError(error) {
|
|
|
99
99
|
}
|
|
100
100
|
return messages.join(' ');
|
|
101
101
|
}
|
|
102
|
-
/** Machine-code classification
|
|
102
|
+
/** Machine-code classification shared by tool results and api_usage. Never rewrite legacy codes.
|
|
103
103
|
* Keys are case-insensitive; every supported legacy spelling is listed explicitly.
|
|
104
104
|
* Existing usage-only policy classes remain supported alongside the six tool classes. */
|
|
105
105
|
export const API_USAGE_ERROR_CODE_MAP = {
|
|
@@ -111,6 +111,7 @@ export const API_USAGE_ERROR_CODE_MAP = {
|
|
|
111
111
|
'bad_request': 'validation_failed',
|
|
112
112
|
'campaigns_required': 'validation_failed',
|
|
113
113
|
'content_required': 'validation_failed',
|
|
114
|
+
'content_not_ready': 'validation_failed',
|
|
114
115
|
'empty_audience': 'validation_failed',
|
|
115
116
|
'empty_body': 'validation_failed',
|
|
116
117
|
'empty_cohort': 'validation_failed',
|
|
@@ -146,6 +147,7 @@ export const API_USAGE_ERROR_CODE_MAP = {
|
|
|
146
147
|
'validation_failed': 'validation_failed',
|
|
147
148
|
'approval_not_cancellable': 'conflict',
|
|
148
149
|
'approval_not_pending': 'conflict',
|
|
150
|
+
'already_sent_to_audience': 'conflict',
|
|
149
151
|
'human_decision_required': 'forbidden',
|
|
150
152
|
'23505': 'conflict',
|
|
151
153
|
'conflict': 'conflict',
|
|
@@ -209,10 +211,32 @@ export const API_USAGE_ERROR_CODE_MAP = {
|
|
|
209
211
|
'step_create_failed': 'internal_error',
|
|
210
212
|
'step_lookup_failed': 'internal_error',
|
|
211
213
|
'survey_link_not_ready': 'internal_error',
|
|
214
|
+
'project_connector_unavailable': 'internal_error',
|
|
212
215
|
'sandbox_blocked': 'sandbox_blocked',
|
|
213
216
|
'send_allowlist_refused': 'send_allowlist_refused',
|
|
214
217
|
'rate_limited': 'rate_limited',
|
|
215
218
|
};
|
|
219
|
+
/** One classifier for the additive response class and hosted usage tracking. */
|
|
220
|
+
export function classifyMachineCode(code) {
|
|
221
|
+
const lower = code.toLowerCase().trim();
|
|
222
|
+
if (Object.hasOwn(API_USAGE_ERROR_CODE_MAP, lower))
|
|
223
|
+
return API_USAGE_ERROR_CODE_MAP[lower];
|
|
224
|
+
if (lower.endsWith('_not_found'))
|
|
225
|
+
return 'not_found';
|
|
226
|
+
if (lower.endsWith('_conflict'))
|
|
227
|
+
return 'conflict';
|
|
228
|
+
if (lower.endsWith('_limit_reached') || lower.endsWith('_limit'))
|
|
229
|
+
return 'plan_limit';
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
/** Classify a failed body, preserving any explicitly supplied error_code. */
|
|
233
|
+
export function toolErrorClass(body) {
|
|
234
|
+
if ('error_code' in body)
|
|
235
|
+
return body.error_code;
|
|
236
|
+
if (typeof body.code !== 'string')
|
|
237
|
+
return 'internal_error';
|
|
238
|
+
return classifyMachineCode(body.code);
|
|
239
|
+
}
|
|
216
240
|
/** Add a stable class to refusals without dropping existing fields or success data. */
|
|
217
241
|
export function codedToolResult(result) {
|
|
218
242
|
let failed = result.isError === true;
|
|
@@ -242,18 +266,21 @@ export function codedToolResult(result) {
|
|
|
242
266
|
return block;
|
|
243
267
|
failed = true;
|
|
244
268
|
// An existing code is a frozen client surface, even when it is unfamiliar.
|
|
245
|
-
if ('code' in body)
|
|
246
|
-
|
|
269
|
+
if ('code' in body) {
|
|
270
|
+
if ('error_code' in body)
|
|
271
|
+
return block;
|
|
272
|
+
return { ...block, text: JSON.stringify({ ...body, error_code: toolErrorClass(body) }, null, block.text.includes('\n') ? 2 : undefined) };
|
|
273
|
+
}
|
|
247
274
|
const nestedCode = body.error && typeof body.error === 'object' ? body.error.code : undefined;
|
|
248
275
|
const nestedClass = typeof nestedCode === 'string' ? nestedCode.toLowerCase() : undefined;
|
|
249
276
|
const code = textCode ?? (TOOL_ERROR_CODES.includes(nestedClass) ? nestedClass
|
|
250
277
|
: (body.status === 404 ? 'not_found'
|
|
251
278
|
: body.status === 409 ? 'conflict' : body.status === 422 ? 'validation_failed'
|
|
252
279
|
: body.status === 401 || body.status === 403 ? 'forbidden' : 'internal_error'));
|
|
253
|
-
return { ...block, text: JSON.stringify({ ...body, code }, null, block.text.includes('\n') ? 2 : undefined) };
|
|
280
|
+
return { ...block, text: JSON.stringify({ ...body, code, error_code: toolErrorClass({ ...body, code }) }, null, block.text.includes('\n') ? 2 : undefined) };
|
|
254
281
|
});
|
|
255
282
|
if (failed && !content.some(block => block.type === 'text')) {
|
|
256
|
-
content.push({ type: 'text', text: JSON.stringify(mapDbError(undefined)) });
|
|
283
|
+
content.push({ type: 'text', text: JSON.stringify({ ...mapDbError(undefined), error_code: toolErrorClass(mapDbError(undefined)) }) });
|
|
257
284
|
}
|
|
258
285
|
return failed ? { ...result, isError: true, content } : result;
|
|
259
286
|
}
|
|
@@ -266,7 +293,7 @@ export function withToolErrors(handler) {
|
|
|
266
293
|
catch (error) {
|
|
267
294
|
if (error instanceof McpError && error.code === ErrorCode.UrlElicitationRequired)
|
|
268
295
|
throw error;
|
|
269
|
-
return dbErrorResult(error);
|
|
296
|
+
return codedToolResult(dbErrorResult(error));
|
|
270
297
|
}
|
|
271
298
|
};
|
|
272
299
|
}
|
package/build/tools/campaigns.js
CHANGED
|
@@ -2722,7 +2722,7 @@ Do not include body_html in your response; Sendinel renders body_html from block
|
|
|
2722
2722
|
idempotentHint: false,
|
|
2723
2723
|
openWorldHint: true,
|
|
2724
2724
|
},
|
|
2725
|
-
description: 'Send a test email to a specified address using the site\'s configured provider. Content from step_id, draft_id, or raw subject/body_html uses the real send renderer. Optional dry_run previews without sending; suppressed recipients are refused. Logged as test, not counted in campaign metrics.',
|
|
2725
|
+
description: 'Send a test email to a specified address using the site\'s configured provider. Content from step_id, draft_id, or raw subject/body_html uses the real send renderer. Optional dry_run previews without sending and includes unresolved_merge_tags (tags with no recipient value and no fallback, with subject/html/text locations); suppressed recipients are refused. Logged as test, not counted in campaign metrics.',
|
|
2726
2726
|
inputSchema: {
|
|
2727
2727
|
approval_id: z.string().uuid().optional().describe('Get this by calling once without it, then have a human approve the returned approve_url. Re-call with only approval_id to run the action.'),
|
|
2728
2728
|
to_email: z.string().email().describe('Email address to send the test to'),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendinel/mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.219",
|
|
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",
|