@sendinel/mcp-server 1.0.223 → 1.0.225
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.
|
@@ -11,7 +11,7 @@ import { logTesterRequestAudit } from './tester-request-audit.js';
|
|
|
11
11
|
import { approvalStore } from './tester-requests-store.js';
|
|
12
12
|
import { createHash } from 'node:crypto';
|
|
13
13
|
import { approvalSetupSummary, buildApprovalPreview, isHumanApprovalChannel, triggerChangeSummary, decodeHtmlEntities, stripHtmlComments } from '@sendinel/domain';
|
|
14
|
-
import { requestContext } from '../db.js';
|
|
14
|
+
import { adminDb, requestContext } from '../db.js';
|
|
15
15
|
import { getProjectId } from '../project.js';
|
|
16
16
|
import { captureApprovalSnapshot, withoutApprovalSnapshot, withoutApprovalDisplay } from './approval-snapshot.js';
|
|
17
17
|
import { fireWebhookEvent } from './webhook-events.js';
|
|
@@ -705,7 +705,31 @@ export function withApproval(action, handler, options = {}) {
|
|
|
705
705
|
let decidedBy;
|
|
706
706
|
let decisionChannel;
|
|
707
707
|
let consumedAt;
|
|
708
|
-
if (decision.tier
|
|
708
|
+
if (decision.tier === 'autonomous') {
|
|
709
|
+
try {
|
|
710
|
+
await assertResourcesBelongToActiveProject(action, params);
|
|
711
|
+
}
|
|
712
|
+
catch (error) {
|
|
713
|
+
if (!(error instanceof ResourceProjectRefusal))
|
|
714
|
+
throw error;
|
|
715
|
+
const actor = requestContext();
|
|
716
|
+
try {
|
|
717
|
+
const { error: auditError } = await adminDb().schema('email').from('audit_log').insert({
|
|
718
|
+
project_id: getProjectId(), actor_type: actor?.actorType ?? 'mcp', actor_id: actor?.actorId ?? null,
|
|
719
|
+
action: 'approval.resource_project_refused', resource_type: 'approval', channel: channelContext.channel,
|
|
720
|
+
details: { action, tool: action, owner_project_id: error.ownerProjectId },
|
|
721
|
+
});
|
|
722
|
+
if (auditError)
|
|
723
|
+
throw auditError;
|
|
724
|
+
}
|
|
725
|
+
catch {
|
|
726
|
+
// An unavailable audit store must never turn a refusal into execution.
|
|
727
|
+
console.warn('[mcp] Could not audit resource project refusal; request remains refused.');
|
|
728
|
+
}
|
|
729
|
+
return plainRefusalResult(error.message);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
709
733
|
if (!approval_id) {
|
|
710
734
|
const display = options.display ? await options.display(params) : undefined;
|
|
711
735
|
try {
|
package/build/lib/db-error.d.ts
CHANGED
|
@@ -35,6 +35,12 @@ export declare function toolError(body: unknown): {
|
|
|
35
35
|
*/
|
|
36
36
|
export declare class PlainToolRefusal extends Error {
|
|
37
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Refusal class for plain refusals (#4811). The text stays the bare sentence, so the class rides in
|
|
40
|
+
* `_meta.error_code`: it survives the in-process MCP client hop behind invoke_tool, which clones the
|
|
41
|
+
* result and loses WeakSet identity. Foreign, missing and malformed ids share it (no existence oracle).
|
|
42
|
+
*/
|
|
43
|
+
export declare const PLAIN_REFUSAL_ERROR_CODE: ToolErrorCode;
|
|
38
44
|
/** The refusal as tool text with isError, exempt from JSON re-coding by codedToolResult. */
|
|
39
45
|
export declare function plainRefusalResult(message: string): {
|
|
40
46
|
isError: true;
|
|
@@ -42,6 +48,9 @@ export declare function plainRefusalResult(message: string): {
|
|
|
42
48
|
type: 'text';
|
|
43
49
|
text: string;
|
|
44
50
|
}[];
|
|
51
|
+
_meta: {
|
|
52
|
+
error_code: "conflict" | "forbidden" | "internal_error" | "not_found" | "plan_limit" | "validation_failed";
|
|
53
|
+
};
|
|
45
54
|
};
|
|
46
55
|
/** A table known to block a delete. `count` is best-effort; it may throw or return null. */
|
|
47
56
|
export interface DeleteBlocker {
|
package/build/lib/db-error.js
CHANGED
|
@@ -55,9 +55,23 @@ export function toolError(body) {
|
|
|
55
55
|
export class PlainToolRefusal extends Error {
|
|
56
56
|
}
|
|
57
57
|
const plainRefusalResults = new WeakSet();
|
|
58
|
+
/**
|
|
59
|
+
* Refusal class for plain refusals (#4811). The text stays the bare sentence, so the class rides in
|
|
60
|
+
* `_meta.error_code`: it survives the in-process MCP client hop behind invoke_tool, which clones the
|
|
61
|
+
* result and loses WeakSet identity. Foreign, missing and malformed ids share it (no existence oracle).
|
|
62
|
+
*/
|
|
63
|
+
export const PLAIN_REFUSAL_ERROR_CODE = 'not_found';
|
|
64
|
+
function hasPlainRefusalMeta(result) {
|
|
65
|
+
const meta = result?._meta;
|
|
66
|
+
return meta?.error_code === PLAIN_REFUSAL_ERROR_CODE;
|
|
67
|
+
}
|
|
58
68
|
/** The refusal as tool text with isError, exempt from JSON re-coding by codedToolResult. */
|
|
59
69
|
export function plainRefusalResult(message) {
|
|
60
|
-
const result = {
|
|
70
|
+
const result = {
|
|
71
|
+
isError: true,
|
|
72
|
+
content: [{ type: 'text', text: message }],
|
|
73
|
+
_meta: { error_code: PLAIN_REFUSAL_ERROR_CODE },
|
|
74
|
+
};
|
|
61
75
|
plainRefusalResults.add(result);
|
|
62
76
|
return result;
|
|
63
77
|
}
|
|
@@ -253,7 +267,7 @@ export function toolErrorClass(body) {
|
|
|
253
267
|
}
|
|
254
268
|
/** Add a stable class to refusals without dropping existing fields or success data. */
|
|
255
269
|
export function codedToolResult(result) {
|
|
256
|
-
if (plainRefusalResults.has(result))
|
|
270
|
+
if (plainRefusalResults.has(result) || (result.isError === true && hasPlainRefusalMeta(result)))
|
|
257
271
|
return result;
|
|
258
272
|
let failed = result.isError === true;
|
|
259
273
|
const content = result.content.map(block => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendinel/mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.225",
|
|
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",
|