@auctra/mcp-gateway 0.1.4 → 0.1.6
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/README.md +18 -0
- package/package.json +1 -1
- package/src/index.js +33 -0
- package/src/index.ts +105 -0
package/README.md
CHANGED
|
@@ -30,6 +30,24 @@ const sendEmail = withAuctraGate({
|
|
|
30
30
|
|
|
31
31
|
Blocked or approval-required tool calls throw `McpToolBlockedError` with the decision evidence hash when present.
|
|
32
32
|
|
|
33
|
+
## NL→SQL data scope (`gateMcpSqlQuery`)
|
|
34
|
+
|
|
35
|
+
Declare requested vs authorized query scope so the production gate can emit `SQL_SCOPE_EXCEEDED`:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { gateMcpSqlQuery } from "@auctra/mcp-gateway";
|
|
39
|
+
|
|
40
|
+
await gateMcpSqlQuery({
|
|
41
|
+
client,
|
|
42
|
+
agentId: "agent-uuid",
|
|
43
|
+
toolName: "customer_query",
|
|
44
|
+
requestedScope: "customers.*",
|
|
45
|
+
authorizedScope: "customers.aggregate_metrics",
|
|
46
|
+
claimedIntentId: intent.id,
|
|
47
|
+
intentAnchorToken: intent.anchor_token,
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
33
51
|
## Engine 15 — MCP / skill install attestation
|
|
34
52
|
|
|
35
53
|
High-impact installs require `mcp_install` + HMAC `supply_chain_attestation` on the gate.
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -181,6 +181,39 @@ export async function gateMcpToolCall(input) {
|
|
|
181
181
|
throw new McpToolBlockedError(message, result.decision, result.evidence);
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
+
const requireLease = process.env.AUCTRA_REQUIRE_EXECUTION_LEASE === "1";
|
|
185
|
+
const leaseToken = result.execution_lease?.token;
|
|
186
|
+
if (requireLease || leaseToken) {
|
|
187
|
+
if (!leaseToken) {
|
|
188
|
+
throw new McpToolBlockedError(
|
|
189
|
+
"execution lease required but action.execute returned none — configure AUCTRA_EXECUTION_LEASE_SECRET",
|
|
190
|
+
"blocked",
|
|
191
|
+
result.evidence,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
if (!input.client.executionLease?.consume) {
|
|
195
|
+
if (requireLease) {
|
|
196
|
+
throw new McpToolBlockedError(
|
|
197
|
+
"executionLease.consume client method required when AUCTRA_REQUIRE_EXECUTION_LEASE=1",
|
|
198
|
+
"blocked",
|
|
199
|
+
result.evidence,
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
const consumed = await input.client.executionLease.consume({
|
|
204
|
+
lease: leaseToken,
|
|
205
|
+
expectedActionType: resolveActionType(input),
|
|
206
|
+
});
|
|
207
|
+
if (!consumed.ok) {
|
|
208
|
+
throw new McpToolBlockedError(
|
|
209
|
+
consumed.error ?? "execution lease consume failed",
|
|
210
|
+
"blocked",
|
|
211
|
+
result.evidence,
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
184
217
|
return result;
|
|
185
218
|
}
|
|
186
219
|
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,12 @@ export type ExecuteActionClient = {
|
|
|
18
18
|
decision: "allowed" | "blocked" | "require_approval";
|
|
19
19
|
reason: string;
|
|
20
20
|
action_request_id?: string;
|
|
21
|
+
execution_lease?: {
|
|
22
|
+
token: string;
|
|
23
|
+
expires_at: string;
|
|
24
|
+
action_request_id: string;
|
|
25
|
+
action_type: string;
|
|
26
|
+
} | null;
|
|
21
27
|
evidence?: {
|
|
22
28
|
format: string;
|
|
23
29
|
payload_hash: string;
|
|
@@ -26,6 +32,13 @@ export type ExecuteActionClient = {
|
|
|
26
32
|
evidence_payload?: { evidence_id?: string };
|
|
27
33
|
}>;
|
|
28
34
|
};
|
|
35
|
+
/** Optional — required when AUCTRA_REQUIRE_EXECUTION_LEASE=1 */
|
|
36
|
+
executionLease?: {
|
|
37
|
+
consume(input: {
|
|
38
|
+
lease: string;
|
|
39
|
+
expectedActionType?: string;
|
|
40
|
+
}): Promise<{ ok: boolean; error?: string; reason_codes?: string[] }>;
|
|
41
|
+
};
|
|
29
42
|
};
|
|
30
43
|
|
|
31
44
|
/** @deprecated Use ExecuteActionClient — kept as type alias for migration notes only */
|
|
@@ -314,6 +327,39 @@ export async function gateMcpToolCall(input: McpToolGateInput) {
|
|
|
314
327
|
throw new McpToolBlockedError(message, result.decision, result.evidence);
|
|
315
328
|
}
|
|
316
329
|
|
|
330
|
+
const requireLease = process.env.AUCTRA_REQUIRE_EXECUTION_LEASE === "1";
|
|
331
|
+
const leaseToken = result.execution_lease?.token;
|
|
332
|
+
if (requireLease || leaseToken) {
|
|
333
|
+
if (!leaseToken) {
|
|
334
|
+
throw new McpToolBlockedError(
|
|
335
|
+
"execution lease required but action.execute returned none — configure AUCTRA_EXECUTION_LEASE_SECRET",
|
|
336
|
+
"blocked",
|
|
337
|
+
result.evidence,
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
if (!input.client.executionLease?.consume) {
|
|
341
|
+
if (requireLease) {
|
|
342
|
+
throw new McpToolBlockedError(
|
|
343
|
+
"executionLease.consume client method required when AUCTRA_REQUIRE_EXECUTION_LEASE=1",
|
|
344
|
+
"blocked",
|
|
345
|
+
result.evidence,
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
} else {
|
|
349
|
+
const consumed = await input.client.executionLease.consume({
|
|
350
|
+
lease: leaseToken,
|
|
351
|
+
expectedActionType: resolveActionType(input),
|
|
352
|
+
});
|
|
353
|
+
if (!consumed.ok) {
|
|
354
|
+
throw new McpToolBlockedError(
|
|
355
|
+
consumed.error ?? "execution lease consume failed",
|
|
356
|
+
"blocked",
|
|
357
|
+
result.evidence,
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
317
363
|
return result;
|
|
318
364
|
}
|
|
319
365
|
|
|
@@ -349,3 +395,62 @@ export function withAuctraGate<TArgs extends Record<string, unknown>, TResult>(
|
|
|
349
395
|
};
|
|
350
396
|
};
|
|
351
397
|
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Gate an NL→SQL / database tool call with declared data scope metadata.
|
|
401
|
+
* Production path: same action.execute gate companies use — requested ⊆ authorized.
|
|
402
|
+
*/
|
|
403
|
+
export async function gateMcpSqlQuery(input: {
|
|
404
|
+
client: ExecuteActionClient;
|
|
405
|
+
agentId: string;
|
|
406
|
+
toolName: string;
|
|
407
|
+
requestedScope: string | string[];
|
|
408
|
+
authorizedScope?: string | string[];
|
|
409
|
+
args?: Record<string, unknown>;
|
|
410
|
+
actionType?: string;
|
|
411
|
+
claimedIntentId?: string;
|
|
412
|
+
intentAnchorToken?: string;
|
|
413
|
+
}) {
|
|
414
|
+
const result = await input.client.action.execute({
|
|
415
|
+
agentId: input.agentId,
|
|
416
|
+
actionType: input.actionType ?? "execute_sql",
|
|
417
|
+
claimedIntentId: input.claimedIntentId,
|
|
418
|
+
intentAnchorToken: input.intentAnchorToken,
|
|
419
|
+
payload: {
|
|
420
|
+
tool: input.toolName,
|
|
421
|
+
arguments: input.args ?? {},
|
|
422
|
+
resource: Array.isArray(input.requestedScope)
|
|
423
|
+
? input.requestedScope[0]
|
|
424
|
+
: input.requestedScope,
|
|
425
|
+
},
|
|
426
|
+
action: {
|
|
427
|
+
target: `mcp-sql:${input.toolName}`,
|
|
428
|
+
description: `SQL/query tool ${input.toolName}`,
|
|
429
|
+
metadata: {
|
|
430
|
+
sql: {
|
|
431
|
+
requested_scope: input.requestedScope,
|
|
432
|
+
...(input.authorizedScope != null
|
|
433
|
+
? { authorized_scope: input.authorizedScope }
|
|
434
|
+
: {}),
|
|
435
|
+
},
|
|
436
|
+
inputs: [
|
|
437
|
+
{
|
|
438
|
+
source: `mcp:${input.toolName}:sql`,
|
|
439
|
+
source_type: "mcp_tool_response",
|
|
440
|
+
trust_level: "untrusted",
|
|
441
|
+
authority: "none",
|
|
442
|
+
claimed_influence: "privilege_escalation",
|
|
443
|
+
},
|
|
444
|
+
],
|
|
445
|
+
},
|
|
446
|
+
},
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
if (result.decision !== "allowed") {
|
|
450
|
+
const evidenceId = evidenceIdFromResult(result);
|
|
451
|
+
const message = evidenceId ? `${result.reason} (evidence: ${evidenceId})` : result.reason;
|
|
452
|
+
throw new McpToolBlockedError(message, result.decision, result.evidence);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return result;
|
|
456
|
+
}
|