troxy-cli 1.8.6 → 1.8.8
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 +81 -3
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -72,6 +72,7 @@ export const api = {
|
|
|
72
72
|
// Evaluate + confirm (agent API key)
|
|
73
73
|
evaluate: (body, apiKey) => request('POST', '/evaluate', { apiKey, body }),
|
|
74
74
|
evaluateEmail: (body, apiKey) => request('POST', '/evaluate/email', { apiKey, body }),
|
|
75
|
+
evaluateLogin: (body, apiKey) => request('POST', '/evaluate/login', { apiKey, body }),
|
|
75
76
|
selfRevoke: (apiKey) => request('POST', '/mcp/self-revoke', { apiKey }),
|
|
76
77
|
confirmPayment: (auditId, body, apiKey) => request('POST', `/payments/${auditId}/confirm`, { apiKey, body }),
|
|
77
78
|
waitApprovalStatus: (token) => request('GET', `/approvals/${encodeURIComponent(token)}/wait`),
|
package/src/mcp-server.js
CHANGED
|
@@ -8,6 +8,7 @@ import { loadConfig } from './config.js';
|
|
|
8
8
|
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
|
+
const evaluateLogin = (body, apiKey) => api.evaluateLogin(body, apiKey);
|
|
11
12
|
|
|
12
13
|
export async function runMcp() {
|
|
13
14
|
const config = loadConfig();
|
|
@@ -40,7 +41,8 @@ export async function runMcp() {
|
|
|
40
41
|
'If the decision is NOTIFY, proceed but the user will be notified. ' +
|
|
41
42
|
'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. ' +
|
|
42
43
|
'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. ' +
|
|
43
|
-
'You MUST also call the evaluate_email tool before sending any email on the user\'s behalf. 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.'
|
|
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_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.',
|
|
44
46
|
},
|
|
45
47
|
{ capabilities: { tools: {} } },
|
|
46
48
|
);
|
|
@@ -142,7 +144,7 @@ export async function runMcp() {
|
|
|
142
144
|
'based on your Troxy policies. Call this before sending any email on the user\'s behalf.',
|
|
143
145
|
inputSchema: {
|
|
144
146
|
type: 'object',
|
|
145
|
-
required: ['recipient'],
|
|
147
|
+
required: ['recipient', 'body'],
|
|
146
148
|
properties: {
|
|
147
149
|
recipient: {
|
|
148
150
|
type: 'string',
|
|
@@ -152,6 +154,13 @@ export async function runMcp() {
|
|
|
152
154
|
type: 'string',
|
|
153
155
|
description: 'Subject line of the email (optional)',
|
|
154
156
|
},
|
|
157
|
+
body: {
|
|
158
|
+
type: 'string',
|
|
159
|
+
description:
|
|
160
|
+
'The full plaintext body of the email, exactly as it will be sent. REQUIRED — ' +
|
|
161
|
+
'Troxy policies scan this to catch secrets, credentials, or confidential content ' +
|
|
162
|
+
'before the email goes out. Never omit, summarize, or truncate it.',
|
|
163
|
+
},
|
|
155
164
|
agent: {
|
|
156
165
|
type: 'string',
|
|
157
166
|
description: 'Name of the agent sending the email (optional)',
|
|
@@ -163,6 +172,35 @@ export async function runMcp() {
|
|
|
163
172
|
},
|
|
164
173
|
},
|
|
165
174
|
},
|
|
175
|
+
{
|
|
176
|
+
name: 'evaluate_login',
|
|
177
|
+
description:
|
|
178
|
+
'Evaluate whether logging into or signing up for a website should be allowed, blocked, or escalated ' +
|
|
179
|
+
'based on your Troxy policies. Call this before submitting login credentials or a signup form on the user\'s behalf.',
|
|
180
|
+
inputSchema: {
|
|
181
|
+
type: 'object',
|
|
182
|
+
required: ['site', 'login_action'],
|
|
183
|
+
properties: {
|
|
184
|
+
site: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
description: 'The domain of the site being logged into or signed up for, e.g. "example.com"',
|
|
187
|
+
},
|
|
188
|
+
login_action: {
|
|
189
|
+
type: 'string',
|
|
190
|
+
enum: ['login', 'signup'],
|
|
191
|
+
description: '"login" if authenticating to an existing account, "signup" if creating a new account',
|
|
192
|
+
},
|
|
193
|
+
agent: {
|
|
194
|
+
type: 'string',
|
|
195
|
+
description: 'Name of the agent performing the login/signup (optional)',
|
|
196
|
+
},
|
|
197
|
+
approval_token: {
|
|
198
|
+
type: 'string',
|
|
199
|
+
description: 'Approval token from a previous ESCALATE response. Include this to proceed after the user has approved.',
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
166
204
|
],
|
|
167
205
|
}));
|
|
168
206
|
|
|
@@ -261,7 +299,7 @@ export async function runMcp() {
|
|
|
261
299
|
emailText = `✗ Email blocked.${reason ? ` ${reason}` : ''} Do not send it. (audit: ${audit_id})`;
|
|
262
300
|
break;
|
|
263
301
|
case 'ESCALATE':
|
|
264
|
-
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 PLUS this approval_token. Do not send until it returns approved.`;
|
|
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.`;
|
|
265
303
|
break;
|
|
266
304
|
default:
|
|
267
305
|
emailText = JSON.stringify(result);
|
|
@@ -272,6 +310,46 @@ export async function runMcp() {
|
|
|
272
310
|
};
|
|
273
311
|
}
|
|
274
312
|
|
|
313
|
+
if (toolName === 'evaluate_login') {
|
|
314
|
+
if (agentName && !args.agent) args.agent = agentName;
|
|
315
|
+
let result;
|
|
316
|
+
try {
|
|
317
|
+
result = await evaluateLogin(args, apiKey);
|
|
318
|
+
} catch (err) {
|
|
319
|
+
return {
|
|
320
|
+
content: [{ type: 'text', text: `Troxy error: ${err.message}` }],
|
|
321
|
+
isError: true,
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (result.error) {
|
|
325
|
+
return {
|
|
326
|
+
content: [{ type: 'text', text: `Troxy error: ${result.error}` }],
|
|
327
|
+
isError: true,
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
const { decision, reason, audit_id, approval_token } = result;
|
|
331
|
+
const verb = args.login_action === 'signup' ? 'Signup' : 'Login';
|
|
332
|
+
let loginText;
|
|
333
|
+
switch (decision) {
|
|
334
|
+
case 'ALLOW':
|
|
335
|
+
case 'NOTIFY':
|
|
336
|
+
loginText = `✓ ${verb} approved.${reason ? ` ${reason}` : ''} You may proceed. (audit: ${audit_id})`;
|
|
337
|
+
break;
|
|
338
|
+
case 'BLOCK':
|
|
339
|
+
loginText = `✗ ${verb} blocked.${reason ? ` ${reason}` : ''} Do not proceed. (audit: ${audit_id})`;
|
|
340
|
+
break;
|
|
341
|
+
case 'ESCALATE':
|
|
342
|
+
loginText = `⏳ ${verb} 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_login again with the same site/login_action PLUS this approval_token. Do not proceed until it returns approved.`;
|
|
343
|
+
break;
|
|
344
|
+
default:
|
|
345
|
+
loginText = JSON.stringify(result);
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
content: [{ type: 'text', text: loginText }],
|
|
349
|
+
isError: decision === 'BLOCK',
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
275
353
|
if (toolName !== 'evaluate_payment') {
|
|
276
354
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
277
355
|
}
|