@sendinel/mcp-server 1.0.178 → 1.0.180

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.
@@ -117,6 +117,7 @@ type ToolResult = {
117
117
  type: 'text';
118
118
  text: string;
119
119
  }>;
120
+ isError?: boolean;
120
121
  };
121
122
  export declare function approvalSatisfied(action: string): boolean;
122
123
  /** Catch preview/draft branches that historically returned before their hand-written gate.
@@ -17,6 +17,7 @@ import { captureApprovalSnapshot, withoutApprovalSnapshot, withoutApprovalDispla
17
17
  import { fireWebhookEvent } from './webhook-events.js';
18
18
  import { offerApprovalApp } from './approval-app.js';
19
19
  import { elicitApproval } from './approval-elicitation.js';
20
+ import { toolError } from './db-error.js';
20
21
  export function getApprovalTier(action, params) {
21
22
  // #4308 / #4214: a request-only connection cannot bypass approval via autonomous/preview modes.
22
23
  const scopes = requestContext()?.scopes;
@@ -291,8 +292,13 @@ export function approvalRetryTool(action, config, handler, nativeReplay = native
291
292
  if (typeof approval_id === 'string' && Object.values(supplied).every(value => value === undefined)) {
292
293
  const { data, error } = await approvalStore().schema('email').from('action_approvals')
293
294
  .select('action, params, payload_hash').eq('id', approval_id).eq('project_id', getProjectId()).eq('action', action).maybeSingle();
294
- if (error || !data)
295
- return toolText(JSON.stringify({ code: 'not_found', error: 'Approval not found for this action and project. Request a new approval.' }));
295
+ if (error || !data) {
296
+ return toolError({
297
+ code: 'not_found',
298
+ error: 'Approval not found for this action and project. Request a new approval.',
299
+ next: 'Call again without approval_id to request a new approval.',
300
+ });
301
+ }
296
302
  if (data.payload_hash && approvalPayloadHash(action, data.params) !== data.payload_hash) {
297
303
  return toolText(JSON.stringify({ code: 'validation_failed', error: 'payload_changed_after_approval' }));
298
304
  }
@@ -670,7 +676,16 @@ export function withApproval(action, handler, options = {}) {
670
676
  consumedAt = check.consumed_at;
671
677
  decisionChannel = check.decision_channel === 'sandbox' ? 'sandbox' : undefined;
672
678
  if (!check.approved) {
673
- return toolText(`Approval ${approval_id} is ${check.status}. ${check.status === 'pending' ? 'Waiting for human approval via dashboard.' : 'Request a new approval.'}`);
679
+ const code = check.status === 'rejected' || check.status === 'human_decision_required' ? 'forbidden'
680
+ : check.status === 'not_found' || check.status === 'action_mismatch' ? 'not_found'
681
+ : 'conflict';
682
+ return toolError({
683
+ code,
684
+ error: `Approval ${approval_id} is ${check.status}. ${check.status === 'pending' ? 'Waiting for human approval via dashboard.' : 'Request a new approval.'}`,
685
+ next: check.status === 'pending'
686
+ ? 'Wait for a person to approve it, then call again with only approval_id.'
687
+ : 'Call again without approval_id to request a new approval.',
688
+ });
674
689
  }
675
690
  }
676
691
  if (options.registeredRequestOnly) {
@@ -91,6 +91,11 @@ export function registerApprovalTools(server, options) {
91
91
  .limit(25);
92
92
  if (error)
93
93
  return toolError(dbToolError(error));
94
- return j({ pending: (data ?? []).map((row) => ({ ...row, ...(row.decided_via === 'sandbox' ? { decision_channel: 'sandbox' } : {}) })), count: data?.length ?? 0 });
94
+ const rows = (data ?? []).map((row) => ({ ...row, ...(row.decided_via === 'sandbox' ? { decision_channel: 'sandbox' } : {}) }));
95
+ return j({
96
+ pending: rows,
97
+ ...(status === 'approved' ? { approvals: rows } : {}),
98
+ count: data?.length ?? 0,
99
+ });
95
100
  });
96
101
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendinel/mcp-server",
3
- "version": "1.0.178",
3
+ "version": "1.0.180",
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",