troxy-cli 1.8.9 → 1.10.0
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/package.json +1 -1
- package/src/api.js +1 -0
- package/src/mcp-server.js +88 -3
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -73,6 +73,7 @@ export const api = {
|
|
|
73
73
|
evaluate: (body, apiKey) => request('POST', '/evaluate', { apiKey, body }),
|
|
74
74
|
evaluateEmail: (body, apiKey) => request('POST', '/evaluate/email', { apiKey, body }),
|
|
75
75
|
evaluateLogin: (body, apiKey) => request('POST', '/evaluate/login', { apiKey, body }),
|
|
76
|
+
evaluateAction: (body, apiKey) => request('POST', '/evaluate/action', { apiKey, body }),
|
|
76
77
|
selfRevoke: (apiKey) => request('POST', '/mcp/self-revoke', { apiKey }),
|
|
77
78
|
confirmPayment: (auditId, body, apiKey) => request('POST', `/payments/${auditId}/confirm`, { apiKey, body }),
|
|
78
79
|
waitApprovalStatus: (token) => request('GET', `/approvals/${encodeURIComponent(token)}/wait`),
|
package/src/mcp-server.js
CHANGED
|
@@ -9,6 +9,7 @@ import { evaluatePayment, api } from './api.js';
|
|
|
9
9
|
const confirmPayment = (auditId, body, apiKey) => api.confirmPayment(auditId, body, apiKey);
|
|
10
10
|
const evaluateEmail = (body, apiKey) => api.evaluateEmail(body, apiKey);
|
|
11
11
|
const evaluateLogin = (body, apiKey) => api.evaluateLogin(body, apiKey);
|
|
12
|
+
const evaluateAction = (body, apiKey) => api.evaluateAction(body, apiKey);
|
|
12
13
|
|
|
13
14
|
export async function runMcp() {
|
|
14
15
|
const config = loadConfig();
|
|
@@ -41,7 +42,8 @@ export async function runMcp() {
|
|
|
41
42
|
'If the decision is NOTIFY, proceed but the user will be notified. ' +
|
|
42
43
|
'When calling evaluate_payment, use the merchant\'s domain name as merchant_name when available (e.g. "amazon.com", "indigobloom.co.il"); this ensures consistent matching against policies. ' +
|
|
43
44
|
'After every ALLOW or NOTIFY decision, attempt the payment, then call confirm_payment with the audit_id and the outcome (success/failed/cancelled). Always include a reason when the charge fails. ' +
|
|
44
|
-
'You MUST also call the evaluate_email tool before sending any email on the user\'s behalf. Always include the full plaintext "body" argument, exactly as you intend to send it — Troxy policies inspect the body for secrets and confidential content, and cannot do so if it is omitted, summarized, or truncated. Never send an email without first receiving an ALLOW or NOTIFY decision. If BLOCK, do not send it. If ESCALATE, call wait_for_payment_approval with the returned approval_token (same wait mechanism payments use), then call evaluate_email again with the approval_token once approved. ' +
|
|
45
|
+
'You MUST also call the evaluate_email tool before sending any email on the user\'s behalf. Always include the full plaintext "body" argument, exactly as you intend to send it — Troxy policies inspect the body for secrets and confidential content, and cannot do so if it is omitted, summarized, or truncated. When the email goes to more than one person (a reply-all, a group, a bulk send), also pass every To/Cc/Bcc address in "recipients" so mass-email policies can apply. Never send an email without first receiving an ALLOW or NOTIFY decision. If BLOCK, do not send it. If ESCALATE, call wait_for_payment_approval with the returned approval_token (same wait mechanism payments use), then call evaluate_email again with the approval_token once approved. ' +
|
|
46
|
+
'You MUST also call the evaluate_action tool before any destructive or hard-to-undo action on the user\'s behalf: deleting files or records, dropping or truncating a table, force-pushing or deleting a branch, destroying infrastructure, revoking access, or overwriting data. Give the verb, what it affects, how many items, and whether it can be undone. Never carry the action out without first receiving an ALLOW or NOTIFY decision. ' +
|
|
45
47
|
'You MUST also call the evaluate_login tool before logging into or signing up for any website on the user\'s behalf, giving the site\'s domain and whether it is a login or a signup. Never submit login credentials or a signup form without first receiving an ALLOW or NOTIFY decision. If BLOCK, do not proceed. If ESCALATE, call wait_for_payment_approval with the returned approval_token, then call evaluate_login again with the approval_token once approved.',
|
|
46
48
|
},
|
|
47
49
|
{ capabilities: { tools: {} } },
|
|
@@ -148,7 +150,16 @@ export async function runMcp() {
|
|
|
148
150
|
properties: {
|
|
149
151
|
recipient: {
|
|
150
152
|
type: 'string',
|
|
151
|
-
description: 'Email address of the recipient',
|
|
153
|
+
description: 'Email address of the primary recipient',
|
|
154
|
+
},
|
|
155
|
+
recipients: {
|
|
156
|
+
type: 'array',
|
|
157
|
+
items: { type: 'string' },
|
|
158
|
+
description:
|
|
159
|
+
'EVERY address the email will reach — all To, Cc, and Bcc recipients, ' +
|
|
160
|
+
'including the primary one. Send this whenever there is more than one ' +
|
|
161
|
+
'recipient (a reply-all, a group, a bulk send), so Troxy policies about ' +
|
|
162
|
+
'mass email can apply. Omit only for a genuine one-to-one email.',
|
|
152
163
|
},
|
|
153
164
|
subject: {
|
|
154
165
|
type: 'string',
|
|
@@ -172,6 +183,49 @@ export async function runMcp() {
|
|
|
172
183
|
},
|
|
173
184
|
},
|
|
174
185
|
},
|
|
186
|
+
{
|
|
187
|
+
name: 'evaluate_action',
|
|
188
|
+
description:
|
|
189
|
+
'Evaluate whether a destructive or hard-to-undo action should be allowed, blocked, or ' +
|
|
190
|
+
'escalated based on your Troxy policies. Call this BEFORE deleting, overwriting, dropping, ' +
|
|
191
|
+
'truncating, force-pushing, destroying, or revoking anything on the user\'s behalf.',
|
|
192
|
+
inputSchema: {
|
|
193
|
+
type: 'object',
|
|
194
|
+
required: ['action_verb'],
|
|
195
|
+
properties: {
|
|
196
|
+
action_verb: {
|
|
197
|
+
type: 'string',
|
|
198
|
+
description:
|
|
199
|
+
'What you are about to do, one lowercase word: delete, overwrite, drop, truncate, ' +
|
|
200
|
+
'force_push, destroy, revoke, deploy, share, upload, or export.',
|
|
201
|
+
},
|
|
202
|
+
resource: {
|
|
203
|
+
type: 'string',
|
|
204
|
+
description:
|
|
205
|
+
'What it affects — a path, table, bucket, repo or branch, e.g. "/var/data", ' +
|
|
206
|
+
'"users", "refs/heads/main". Policies can narrow a rule to a specific target.',
|
|
207
|
+
},
|
|
208
|
+
item_count: {
|
|
209
|
+
type: 'number',
|
|
210
|
+
description:
|
|
211
|
+
'How many things the action affects (files, rows, records). Send the real number ' +
|
|
212
|
+
'whenever you know it — bulk-action policies depend on it. Defaults to 1.',
|
|
213
|
+
},
|
|
214
|
+
reversible: {
|
|
215
|
+
type: 'boolean',
|
|
216
|
+
description:
|
|
217
|
+
'True only if this can be straightforwardly undone (e.g. a soft delete, a revert). ' +
|
|
218
|
+
'If you are unsure, omit it or send false: an undeclared action is treated as ' +
|
|
219
|
+
'irreversible so it is not waved through by mistake.',
|
|
220
|
+
},
|
|
221
|
+
agent: { type: 'string', description: 'Name of the agent (optional)' },
|
|
222
|
+
approval_token: {
|
|
223
|
+
type: 'string',
|
|
224
|
+
description: 'Approval token from a previous ESCALATE response. Include this to proceed after the user has approved.',
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
175
229
|
{
|
|
176
230
|
name: 'evaluate_login',
|
|
177
231
|
description:
|
|
@@ -299,7 +353,7 @@ export async function runMcp() {
|
|
|
299
353
|
emailText = `✗ Email blocked.${reason ? ` ${reason}` : ''} Do not send it. (audit: ${audit_id})`;
|
|
300
354
|
break;
|
|
301
355
|
case 'ESCALATE':
|
|
302
|
-
emailText = `⏳ Email requires human approval; a request has been sent to the account owner.\n\nApproval token: ${approval_token}\n\nNow call wait_for_payment_approval(approval_token="${approval_token}") to automatically detect approval, then call evaluate_email again with the same recipient/subject/body PLUS this approval_token. Do not send until it returns approved.`;
|
|
356
|
+
emailText = `⏳ Email requires human approval; a request has been sent to the account owner.\n\nApproval token: ${approval_token}\n\nNow call wait_for_payment_approval(approval_token="${approval_token}") to automatically detect approval, then call evaluate_email again with the same recipient/recipients/subject/body PLUS this approval_token. Do not send until it returns approved.`;
|
|
303
357
|
break;
|
|
304
358
|
default:
|
|
305
359
|
emailText = JSON.stringify(result);
|
|
@@ -310,6 +364,37 @@ export async function runMcp() {
|
|
|
310
364
|
};
|
|
311
365
|
}
|
|
312
366
|
|
|
367
|
+
if (toolName === 'evaluate_action') {
|
|
368
|
+
if (agentName && !args.agent) args.agent = agentName;
|
|
369
|
+
let result;
|
|
370
|
+
try {
|
|
371
|
+
result = await evaluateAction(args, apiKey);
|
|
372
|
+
} catch (err) {
|
|
373
|
+
return { content: [{ type: 'text', text: `Troxy error: ${err.message}` }], isError: true };
|
|
374
|
+
}
|
|
375
|
+
if (result.error) {
|
|
376
|
+
return { content: [{ type: 'text', text: `Troxy error: ${result.error}` }], isError: true };
|
|
377
|
+
}
|
|
378
|
+
const { decision, reason, audit_id, approval_token } = result;
|
|
379
|
+
const what = `${args.action_verb}${args.resource ? ` on ${args.resource}` : ''}`;
|
|
380
|
+
let actionText;
|
|
381
|
+
switch (decision) {
|
|
382
|
+
case 'ALLOW':
|
|
383
|
+
case 'NOTIFY':
|
|
384
|
+
actionText = `✓ Approved: ${what}.${reason ? ` ${reason}` : ''} You may proceed. (audit: ${audit_id})`;
|
|
385
|
+
break;
|
|
386
|
+
case 'BLOCK':
|
|
387
|
+
actionText = `✗ Blocked: ${what}.${reason ? ` ${reason}` : ''} Do not proceed. (audit: ${audit_id})`;
|
|
388
|
+
break;
|
|
389
|
+
case 'ESCALATE':
|
|
390
|
+
actionText = `⏳ ${what} requires human approval; a request has been sent to the account owner.\n\nApproval token: ${approval_token}\n\nNow call wait_for_payment_approval(approval_token="${approval_token}") to automatically detect approval, then call evaluate_action again with the same arguments PLUS this approval_token. Do not proceed until it returns approved.`;
|
|
391
|
+
break;
|
|
392
|
+
default:
|
|
393
|
+
actionText = JSON.stringify(result);
|
|
394
|
+
}
|
|
395
|
+
return { content: [{ type: 'text', text: actionText }], isError: decision === 'BLOCK' };
|
|
396
|
+
}
|
|
397
|
+
|
|
313
398
|
if (toolName === 'evaluate_login') {
|
|
314
399
|
if (agentName && !args.agent) args.agent = agentName;
|
|
315
400
|
let result;
|