@auctra/mcp-gateway 0.1.10 → 0.1.12
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 +2 -0
- package/package.json +1 -1
- package/src/index.js +52 -38
- package/src/index.ts +55 -36
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@ Stage 0 MCP gateway adapter. Wrap MCP tool calls **and installs** with Auctra **
|
|
|
4
4
|
|
|
5
5
|
**REQUIRE_MCP_GATEWAY:** Production orgs (Startup+) default `require_mcp_gateway=true`. MCP-shaped `action.execute` without this package’s stamp (`auctra_mcp_gateway`) is blocked. Set `AUCTRA_REQUIRE_MCP_GATEWAY=1` for a global fail-closed override.
|
|
6
6
|
|
|
7
|
+
**Execution lease:** `gateMcpToolCall` / `withAuctraGate` require a consumed execution lease after ALLOW. A decision is not permission to run the tool. `AUCTRA_ALLOW_MCP_WITHOUT_LEASE=1` is an unsupported lab opt-out and is ignored when `NODE_ENV=production` or `AUCTRA_EXECUTION_LEASE_SECRET` is set. This package version is local until published.
|
|
8
|
+
|
|
7
9
|
```ts
|
|
8
10
|
import { Auctra } from "@auctra/sdk";
|
|
9
11
|
import {
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -29,6 +29,55 @@ function resolveActionType(input) {
|
|
|
29
29
|
return input.actionType ?? input.actionTypeMap?.[input.toolName] ?? "execute_tool";
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
function isSupportedProductionConfig() {
|
|
33
|
+
if (process.env.NODE_ENV === "production") return true;
|
|
34
|
+
return Boolean(process.env.AUCTRA_EXECUTION_LEASE_SECRET?.trim());
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Lab/dev escape only. Ignored when NODE_ENV=production or
|
|
39
|
+
* AUCTRA_EXECUTION_LEASE_SECRET is set — those are supported production signals.
|
|
40
|
+
*/
|
|
41
|
+
export function allowMcpWithoutLease() {
|
|
42
|
+
if (isSupportedProductionConfig()) return false;
|
|
43
|
+
const v = process.env.AUCTRA_ALLOW_MCP_WITHOUT_LEASE?.trim().toLowerCase();
|
|
44
|
+
return v === "1" || v === "true" || v === "yes";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function assertConsumedExecutionLease(input, result) {
|
|
48
|
+
if (allowMcpWithoutLease()) return;
|
|
49
|
+
const leaseToken = result.execution_lease?.token;
|
|
50
|
+
if (!leaseToken) {
|
|
51
|
+
throw new McpToolBlockedError(
|
|
52
|
+
"execution lease required but action.execute returned none — configure AUCTRA_EXECUTION_LEASE_SECRET",
|
|
53
|
+
"blocked",
|
|
54
|
+
result.evidence,
|
|
55
|
+
result.action_decision ?? null,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
if (!input.client.executionLease?.consume) {
|
|
59
|
+
throw new McpToolBlockedError(
|
|
60
|
+
"executionLease.consume client method required after ALLOW",
|
|
61
|
+
"blocked",
|
|
62
|
+
result.evidence,
|
|
63
|
+
result.action_decision ?? null,
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
const consumed = await input.client.executionLease.consume({
|
|
67
|
+
lease: leaseToken,
|
|
68
|
+
expectedActionType: resolveActionType(input),
|
|
69
|
+
expectedRequestFingerprint: result.execution_lease?.request_fingerprint,
|
|
70
|
+
});
|
|
71
|
+
if (!consumed.ok) {
|
|
72
|
+
throw new McpToolBlockedError(
|
|
73
|
+
consumed.error ?? "execution lease consume failed",
|
|
74
|
+
"blocked",
|
|
75
|
+
result.evidence,
|
|
76
|
+
result.action_decision ?? null,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
32
81
|
function evidenceIdFromResult(result) {
|
|
33
82
|
return result.evidence_payload?.evidence_id ?? result.action_request_id ?? null;
|
|
34
83
|
}
|
|
@@ -199,44 +248,9 @@ export async function gateMcpToolCall(input) {
|
|
|
199
248
|
throw new McpToolBlockedError(message, result.decision, result.evidence, result.action_decision ?? null);
|
|
200
249
|
}
|
|
201
250
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
Boolean(process.env.AUCTRA_EXECUTION_LEASE_SECRET?.trim()));
|
|
206
|
-
const leaseToken = result.execution_lease?.token;
|
|
207
|
-
if (requireLease || leaseToken) {
|
|
208
|
-
if (!leaseToken) {
|
|
209
|
-
throw new McpToolBlockedError(
|
|
210
|
-
"execution lease required but action.execute returned none — configure AUCTRA_EXECUTION_LEASE_SECRET",
|
|
211
|
-
"blocked",
|
|
212
|
-
result.evidence,
|
|
213
|
-
result.action_decision ?? null,
|
|
214
|
-
);
|
|
215
|
-
}
|
|
216
|
-
if (!input.client.executionLease?.consume) {
|
|
217
|
-
if (requireLease) {
|
|
218
|
-
throw new McpToolBlockedError(
|
|
219
|
-
"executionLease.consume client method required when AUCTRA_REQUIRE_EXECUTION_LEASE=1",
|
|
220
|
-
"blocked",
|
|
221
|
-
result.evidence,
|
|
222
|
-
result.action_decision ?? null,
|
|
223
|
-
);
|
|
224
|
-
}
|
|
225
|
-
} else {
|
|
226
|
-
const consumed = await input.client.executionLease.consume({
|
|
227
|
-
lease: leaseToken,
|
|
228
|
-
expectedActionType: resolveActionType(input),
|
|
229
|
-
});
|
|
230
|
-
if (!consumed.ok) {
|
|
231
|
-
throw new McpToolBlockedError(
|
|
232
|
-
consumed.error ?? "execution lease consume failed",
|
|
233
|
-
"blocked",
|
|
234
|
-
result.evidence,
|
|
235
|
-
result.action_decision ?? null,
|
|
236
|
-
);
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
}
|
|
251
|
+
// Default fail-closed (P5-F-007). AUCTRA_REQUIRE_EXECUTION_LEASE remains a
|
|
252
|
+
// recognized alias; AUCTRA_ALLOW_MCP_WITHOUT_LEASE=1 is the only opt-out.
|
|
253
|
+
await assertConsumedExecutionLease(input, result);
|
|
240
254
|
|
|
241
255
|
return result;
|
|
242
256
|
}
|
package/src/index.ts
CHANGED
|
@@ -42,6 +42,7 @@ export type ExecuteActionClient = {
|
|
|
42
42
|
expires_at: string;
|
|
43
43
|
action_request_id: string;
|
|
44
44
|
action_type: string;
|
|
45
|
+
request_fingerprint?: string;
|
|
45
46
|
} | null;
|
|
46
47
|
evidence?: {
|
|
47
48
|
format: string;
|
|
@@ -51,11 +52,12 @@ export type ExecuteActionClient = {
|
|
|
51
52
|
evidence_payload?: { evidence_id?: string };
|
|
52
53
|
}>;
|
|
53
54
|
};
|
|
54
|
-
/**
|
|
55
|
+
/** Required after ALLOW. Lab opt-out is ignored in supported production configs. */
|
|
55
56
|
executionLease?: {
|
|
56
57
|
consume(input: {
|
|
57
58
|
lease: string;
|
|
58
59
|
expectedActionType?: string;
|
|
60
|
+
expectedRequestFingerprint?: string;
|
|
59
61
|
}): Promise<{ ok: boolean; error?: string; reason_codes?: string[] }>;
|
|
60
62
|
};
|
|
61
63
|
};
|
|
@@ -121,6 +123,55 @@ function resolveActionType(input: McpToolGateInput) {
|
|
|
121
123
|
return input.actionType ?? input.actionTypeMap?.[input.toolName] ?? "execute_tool";
|
|
122
124
|
}
|
|
123
125
|
|
|
126
|
+
function isSupportedProductionConfig(): boolean {
|
|
127
|
+
if (process.env.NODE_ENV === "production") return true;
|
|
128
|
+
return Boolean(process.env.AUCTRA_EXECUTION_LEASE_SECRET?.trim());
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Lab/dev escape only. Ignored when NODE_ENV=production or
|
|
133
|
+
* AUCTRA_EXECUTION_LEASE_SECRET is set — those are supported production signals.
|
|
134
|
+
*/
|
|
135
|
+
export function allowMcpWithoutLease(): boolean {
|
|
136
|
+
if (isSupportedProductionConfig()) return false;
|
|
137
|
+
const v = process.env.AUCTRA_ALLOW_MCP_WITHOUT_LEASE?.trim().toLowerCase();
|
|
138
|
+
return v === "1" || v === "true" || v === "yes";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
async function assertConsumedExecutionLease(
|
|
142
|
+
input: McpToolGateInput,
|
|
143
|
+
result: Awaited<ReturnType<ExecuteActionClient["action"]["execute"]>>,
|
|
144
|
+
) {
|
|
145
|
+
if (allowMcpWithoutLease()) return;
|
|
146
|
+
const leaseToken = result.execution_lease?.token;
|
|
147
|
+
if (!leaseToken) {
|
|
148
|
+
throw new McpToolBlockedError(
|
|
149
|
+
"execution lease required but action.execute returned none — configure AUCTRA_EXECUTION_LEASE_SECRET",
|
|
150
|
+
"blocked",
|
|
151
|
+
result.evidence,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (!input.client.executionLease?.consume) {
|
|
155
|
+
throw new McpToolBlockedError(
|
|
156
|
+
"executionLease.consume client method required after ALLOW",
|
|
157
|
+
"blocked",
|
|
158
|
+
result.evidence,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
const consumed = await input.client.executionLease.consume({
|
|
162
|
+
lease: leaseToken,
|
|
163
|
+
expectedActionType: resolveActionType(input),
|
|
164
|
+
expectedRequestFingerprint: result.execution_lease?.request_fingerprint,
|
|
165
|
+
});
|
|
166
|
+
if (!consumed.ok) {
|
|
167
|
+
throw new McpToolBlockedError(
|
|
168
|
+
consumed.error ?? "execution lease consume failed",
|
|
169
|
+
"blocked",
|
|
170
|
+
result.evidence,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
124
175
|
function evidenceIdFromResult(
|
|
125
176
|
result: Awaited<ReturnType<ExecuteActionClient["action"]["execute"]>>,
|
|
126
177
|
) {
|
|
@@ -351,41 +402,9 @@ export async function gateMcpToolCall(input: McpToolGateInput) {
|
|
|
351
402
|
throw new McpToolBlockedError(message, result.decision, result.evidence);
|
|
352
403
|
}
|
|
353
404
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
Boolean(process.env.AUCTRA_EXECUTION_LEASE_SECRET?.trim()));
|
|
358
|
-
const leaseToken = result.execution_lease?.token;
|
|
359
|
-
if (requireLease || leaseToken) {
|
|
360
|
-
if (!leaseToken) {
|
|
361
|
-
throw new McpToolBlockedError(
|
|
362
|
-
"execution lease required but action.execute returned none — configure AUCTRA_EXECUTION_LEASE_SECRET",
|
|
363
|
-
"blocked",
|
|
364
|
-
result.evidence,
|
|
365
|
-
);
|
|
366
|
-
}
|
|
367
|
-
if (!input.client.executionLease?.consume) {
|
|
368
|
-
if (requireLease) {
|
|
369
|
-
throw new McpToolBlockedError(
|
|
370
|
-
"executionLease.consume client method required when AUCTRA_REQUIRE_EXECUTION_LEASE=1",
|
|
371
|
-
"blocked",
|
|
372
|
-
result.evidence,
|
|
373
|
-
);
|
|
374
|
-
}
|
|
375
|
-
} else {
|
|
376
|
-
const consumed = await input.client.executionLease.consume({
|
|
377
|
-
lease: leaseToken,
|
|
378
|
-
expectedActionType: resolveActionType(input),
|
|
379
|
-
});
|
|
380
|
-
if (!consumed.ok) {
|
|
381
|
-
throw new McpToolBlockedError(
|
|
382
|
-
consumed.error ?? "execution lease consume failed",
|
|
383
|
-
"blocked",
|
|
384
|
-
result.evidence,
|
|
385
|
-
);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
405
|
+
// Default fail-closed (P5-F-007). AUCTRA_REQUIRE_EXECUTION_LEASE remains a
|
|
406
|
+
// recognized alias; AUCTRA_ALLOW_MCP_WITHOUT_LEASE=1 is the only opt-out.
|
|
407
|
+
await assertConsumedExecutionLease(input, result);
|
|
389
408
|
|
|
390
409
|
return result;
|
|
391
410
|
}
|