@agentwares/agentguard 0.1.2 → 0.1.4
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 +35 -17
- package/dist/cli.js +349 -155
- package/dist/cli.js.map +1 -1
- package/dist/fixtures/crm-server.js +92 -28
- package/dist/fixtures/crm-server.js.map +1 -1
- package/dist/fixtures/demo-agent.js +0 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +248 -54
- package/dist/index.js.map +1 -1
- package/package.json +16 -16
- package/server.json +2 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// ../../packages/mcp-kit/dist/chunk-
|
|
3
|
+
// ../../packages/mcp-kit/dist/chunk-7LRFDQNC.js
|
|
4
4
|
import { completable } from "@modelcontextprotocol/sdk/server/completable.js";
|
|
5
5
|
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
6
|
import {
|
|
@@ -12,6 +12,19 @@ import {
|
|
|
12
12
|
import { z } from "zod";
|
|
13
13
|
|
|
14
14
|
// ../../packages/x402/dist/index.js
|
|
15
|
+
var USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
16
|
+
var USDC_DECIMALS = 6;
|
|
17
|
+
var USDC_EIP712_DOMAIN = { name: "USD Coin", version: "2" };
|
|
18
|
+
function toAtomicUnits(amountUsd, decimals = USDC_DECIMALS) {
|
|
19
|
+
const trimmed = amountUsd.trim();
|
|
20
|
+
if (!/^\d+(\.\d+)?$/.test(trimmed)) throw new Error(`not a decimal amount: ${amountUsd}`);
|
|
21
|
+
const [whole = "0", fraction = ""] = trimmed.split(".");
|
|
22
|
+
if (fraction.length > decimals) {
|
|
23
|
+
throw new Error(`${amountUsd} has more than ${decimals} decimal places`);
|
|
24
|
+
}
|
|
25
|
+
return `${whole}${fraction.padEnd(decimals, "0")}`.replace(/^0+(?=\d)/, "");
|
|
26
|
+
}
|
|
27
|
+
var DEFAULT_X402_NETWORK = "eip155:8453";
|
|
15
28
|
var X402_HEADER = "X-Payment-Requirements";
|
|
16
29
|
var X402_REQUIRED_HEADER = "PAYMENT-REQUIRED";
|
|
17
30
|
function toAmount(priceUsd) {
|
|
@@ -21,42 +34,69 @@ function toAmount(priceUsd) {
|
|
|
21
34
|
}
|
|
22
35
|
function buildPaymentRequired(opts) {
|
|
23
36
|
const amountUsd = toAmount(opts.priceUsd);
|
|
24
|
-
const
|
|
25
|
-
|
|
37
|
+
const creditsPayTo = opts.creditsPayTo ?? opts.selfServe?.keysUrl;
|
|
38
|
+
const accepts = [];
|
|
39
|
+
if (opts.payTo) {
|
|
40
|
+
accepts.push({
|
|
26
41
|
rail: "x402",
|
|
42
|
+
scheme: "exact",
|
|
27
43
|
amountUsd,
|
|
44
|
+
amount: toAtomicUnits(amountUsd, opts.assetDecimals),
|
|
28
45
|
resource: opts.resource,
|
|
29
46
|
description: opts.description,
|
|
30
|
-
|
|
31
|
-
|
|
47
|
+
mimeType: "application/json",
|
|
48
|
+
network: opts.network ?? DEFAULT_X402_NETWORK,
|
|
49
|
+
asset: opts.asset ?? USDC_BASE,
|
|
50
|
+
extra: opts.assetDomain ?? USDC_EIP712_DOMAIN,
|
|
32
51
|
payTo: opts.payTo,
|
|
33
|
-
maxTimeoutSeconds: 300
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
52
|
+
maxTimeoutSeconds: 300,
|
|
53
|
+
...opts.bazaar ? { bazaar: opts.bazaar } : {}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (creditsPayTo) {
|
|
57
|
+
accepts.push({
|
|
58
|
+
rail: "prepaid_credits",
|
|
37
59
|
amountUsd,
|
|
38
60
|
resource: opts.resource,
|
|
39
61
|
description: opts.description,
|
|
40
62
|
currency: "usd",
|
|
41
|
-
payTo:
|
|
42
|
-
maxTimeoutSeconds: 300
|
|
43
|
-
|
|
44
|
-
|
|
63
|
+
payTo: creditsPayTo,
|
|
64
|
+
maxTimeoutSeconds: 300,
|
|
65
|
+
// funding a balance ends at a hosted Stripe Checkout page, which an agent cannot fill in
|
|
66
|
+
humanRequired: true
|
|
67
|
+
});
|
|
68
|
+
}
|
|
45
69
|
const live = opts.live === true;
|
|
70
|
+
const selfServe = opts.selfServe;
|
|
71
|
+
const x402Rail = accepts.find((a) => a.rail === "x402" && a.payTo);
|
|
72
|
+
const usdcFix = x402Rail ? `Pay in USDC with no account and no human: take the \`accepts\` entry with \`rail: "x402"\`, sign an EIP-3009 transferWithAuthorization for ${x402Rail.amountUsd} USDC to ${x402Rail.payTo} on ${x402Rail.network}, and retry with it base64 in the X-PAYMENT header. The facilitator submits the transfer, so you need USDC and no gas. ` : "";
|
|
73
|
+
const sampleFix = opts.sampleMode ? "Free first: retry with sample=true \u2014 no key, no payment. " : "";
|
|
74
|
+
const cardFix = selfServe ? `Or pay by card: POST ${selfServe.keysUrl} (no auth, no signup) returns a key and a Stripe Checkout URL. Funding that key needs a person at a browser; if you are running unattended, surface the URL to your operator rather than retrying, or use the USDC rail above. Once funded, send Authorization: Bearer <key>, plus Idempotency-Key so a repeated call is charged once.` : "";
|
|
75
|
+
const liveFix = usdcFix || cardFix ? `${sampleFix}${usdcFix}${cardFix}`.trim() : "Retry with a PAYMENT header satisfying one of `accepts`, or send an API key with credit balance.";
|
|
46
76
|
const body = {
|
|
47
77
|
code: "PAYMENT_REQUIRED",
|
|
48
78
|
cause: live ? `This call costs $${amountUsd}. No valid payment or credit was presented.` : `This call costs $${amountUsd}. Pay-per-call (x402 / Stripe MPP) is coming soon; use an API key with prepaid credits.`,
|
|
49
|
-
fix: live ?
|
|
79
|
+
fix: live ? liveFix : `Create an API key${opts.signupUrl ? ` at ${opts.signupUrl}` : ""} and retry with Authorization: Bearer <key>. Try the free sample mode first.`,
|
|
50
80
|
retryable: true,
|
|
51
81
|
priceUsd: opts.priceUsd,
|
|
52
82
|
accepts,
|
|
53
83
|
comingSoon: !live,
|
|
54
|
-
alternatives: [
|
|
84
|
+
alternatives: [
|
|
85
|
+
...creditsPayTo ? ["api_key_credits"] : [],
|
|
86
|
+
...opts.sampleMode ? ["sample_mode"] : []
|
|
87
|
+
],
|
|
88
|
+
...selfServe ? { selfServe } : {},
|
|
89
|
+
...opts.bazaar ? { extensions: { bazaar: opts.bazaar } } : {}
|
|
55
90
|
};
|
|
56
|
-
const encoded = JSON.stringify({
|
|
91
|
+
const encoded = JSON.stringify({
|
|
92
|
+
x402Version: 2,
|
|
93
|
+
accepts,
|
|
94
|
+
resource: opts.resource,
|
|
95
|
+
...opts.bazaar ? { extensions: { bazaar: opts.bazaar } } : {}
|
|
96
|
+
});
|
|
57
97
|
const headers = {
|
|
58
98
|
"Content-Type": "application/json",
|
|
59
|
-
"WWW-Authenticate": `Payment realm="agentwares", methods="x402
|
|
99
|
+
"WWW-Authenticate": `Payment realm="agentwares", methods="x402 prepaid_credits", price="${amountUsd} USD"`,
|
|
60
100
|
[X402_HEADER]: encoded,
|
|
61
101
|
[X402_REQUIRED_HEADER]: btoa(encoded),
|
|
62
102
|
"Cache-Control": "no-store"
|
|
@@ -74,7 +114,7 @@ var StubVerifier = class {
|
|
|
74
114
|
}
|
|
75
115
|
};
|
|
76
116
|
|
|
77
|
-
// ../../packages/mcp-kit/dist/chunk-
|
|
117
|
+
// ../../packages/mcp-kit/dist/chunk-7LRFDQNC.js
|
|
78
118
|
import { z as z2 } from "zod";
|
|
79
119
|
import { z as z3 } from "zod";
|
|
80
120
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
@@ -521,6 +561,7 @@ function withPayment(tool, opts) {
|
|
|
521
561
|
);
|
|
522
562
|
}
|
|
523
563
|
const verifier = opts.verifier ?? new StubVerifier();
|
|
564
|
+
const liveRail = opts.verifier !== void 0;
|
|
524
565
|
const input = tool.input.extend({
|
|
525
566
|
[sampleField]: z2.boolean().default(false).describe(
|
|
526
567
|
"Set true to return an example response at no charge (sample mode). Default false."
|
|
@@ -545,23 +586,46 @@ function withPayment(tool, opts) {
|
|
|
545
586
|
if (auth.ok) return tool.handler(record, { ...ctx, userId: auth.userId });
|
|
546
587
|
reason = auth.reason;
|
|
547
588
|
}
|
|
589
|
+
const resource = ctx.resourceUrl ?? tool.name;
|
|
548
590
|
const required = buildPaymentRequired({
|
|
549
|
-
resource
|
|
591
|
+
resource,
|
|
550
592
|
priceUsd: opts.priceUsd,
|
|
551
593
|
live: opts.live,
|
|
552
594
|
description: opts.description,
|
|
553
595
|
payTo: opts.payTo,
|
|
554
|
-
|
|
596
|
+
creditsPayTo: opts.creditsPayTo,
|
|
597
|
+
signupUrl: opts.signupUrl,
|
|
598
|
+
selfServe: opts.selfServe,
|
|
599
|
+
// withPayment always adds a free `sample` flag to the tool's input schema
|
|
600
|
+
sampleMode: true,
|
|
601
|
+
...opts.bazaar ? { bazaar: opts.bazaar } : {}
|
|
555
602
|
});
|
|
556
|
-
const
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
603
|
+
const advertised = required.body.accepts.find((a) => a.rail === "prepaid_credits") ?? required.body.accepts[0];
|
|
604
|
+
const requirement = advertised ?? {
|
|
605
|
+
rail: "prepaid_credits",
|
|
606
|
+
amountUsd: String(required.body.priceUsd),
|
|
607
|
+
resource,
|
|
608
|
+
...opts.description ? { description: opts.description } : {}
|
|
609
|
+
};
|
|
610
|
+
const verified = await verifier.verify(
|
|
611
|
+
new Request(`https://mcp.local/${tool.name}`, { headers: ctx.headers }),
|
|
612
|
+
requirement
|
|
613
|
+
);
|
|
614
|
+
if (verified.ok) {
|
|
615
|
+
let result;
|
|
616
|
+
try {
|
|
617
|
+
result = await tool.handler(record, ctx);
|
|
618
|
+
} catch (error) {
|
|
619
|
+
await opts.onPaidFailure?.(ctx, verified, error);
|
|
620
|
+
throw error;
|
|
621
|
+
}
|
|
622
|
+
const settled = await verifier.settle?.(verified);
|
|
623
|
+
if (settled && !settled.ok) {
|
|
624
|
+
opts.onSettlementFailure?.(ctx, verified, settled.reason);
|
|
625
|
+
}
|
|
626
|
+
return result;
|
|
564
627
|
}
|
|
628
|
+
reason = liveRail ? verified.reason ?? reason : reason ?? verified.reason;
|
|
565
629
|
throw paymentRequiredError(required.body, reason);
|
|
566
630
|
}
|
|
567
631
|
});
|