@agentwares/agentguard 0.1.3 → 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/dist/cli.js CHANGED
@@ -937,7 +937,7 @@ import {
937
937
  } from "@agentwares/agentguard-core/node";
938
938
  import { existsSync as exists, readFileSync as readFileSync2 } from "fs";
939
939
 
940
- // ../../packages/mcp-kit/dist/chunk-NF4BQXVM.js
940
+ // ../../packages/mcp-kit/dist/chunk-7LRFDQNC.js
941
941
  import { completable } from "@modelcontextprotocol/sdk/server/completable.js";
942
942
  import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
943
943
  import {
@@ -949,6 +949,18 @@ import {
949
949
  import { z } from "zod";
950
950
 
951
951
  // ../../packages/x402/dist/index.js
952
+ var USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
953
+ var USDC_DECIMALS = 6;
954
+ var USDC_EIP712_DOMAIN = { name: "USD Coin", version: "2" };
955
+ function toAtomicUnits(amountUsd, decimals = USDC_DECIMALS) {
956
+ const trimmed = amountUsd.trim();
957
+ if (!/^\d+(\.\d+)?$/.test(trimmed)) throw new Error(`not a decimal amount: ${amountUsd}`);
958
+ const [whole = "0", fraction = ""] = trimmed.split(".");
959
+ if (fraction.length > decimals) {
960
+ throw new Error(`${amountUsd} has more than ${decimals} decimal places`);
961
+ }
962
+ return `${whole}${fraction.padEnd(decimals, "0")}`.replace(/^0+(?=\d)/, "");
963
+ }
952
964
  var DEFAULT_X402_NETWORK = "eip155:8453";
953
965
  var X402_HEADER = "X-Payment-Requirements";
954
966
  var X402_REQUIRED_HEADER = "PAYMENT-REQUIRED";
@@ -964,13 +976,18 @@ function buildPaymentRequired(opts) {
964
976
  if (opts.payTo) {
965
977
  accepts.push({
966
978
  rail: "x402",
979
+ scheme: "exact",
967
980
  amountUsd,
981
+ amount: toAtomicUnits(amountUsd, opts.assetDecimals),
968
982
  resource: opts.resource,
969
983
  description: opts.description,
984
+ mimeType: "application/json",
970
985
  network: opts.network ?? DEFAULT_X402_NETWORK,
971
- asset: "USDC",
986
+ asset: opts.asset ?? USDC_BASE,
987
+ extra: opts.assetDomain ?? USDC_EIP712_DOMAIN,
972
988
  payTo: opts.payTo,
973
- maxTimeoutSeconds: 300
989
+ maxTimeoutSeconds: 300,
990
+ ...opts.bazaar ? { bazaar: opts.bazaar } : {}
974
991
  });
975
992
  }
976
993
  if (creditsPayTo) {
@@ -988,7 +1005,11 @@ function buildPaymentRequired(opts) {
988
1005
  }
989
1006
  const live = opts.live === true;
990
1007
  const selfServe = opts.selfServe;
991
- const liveFix = selfServe ? `Free first: retry with sample=true \u2014 no key, no payment. To pay: POST ${selfServe.keysUrl} (no auth, no signup) returns a key and a Stripe Checkout URL. Funding that key needs a person to complete the Checkout page in a browser; if you are running unattended, surface the URL to your operator rather than retrying. Once funded, send Authorization: Bearer <key>, plus Idempotency-Key so a repeated call is charged once.` : "Retry with a PAYMENT header satisfying one of `accepts`, or send an API key with credit balance.";
1008
+ const x402Rail = accepts.find((a) => a.rail === "x402" && a.payTo);
1009
+ 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. ` : "";
1010
+ const sampleFix = opts.sampleMode ? "Free first: retry with sample=true \u2014 no key, no payment. " : "";
1011
+ 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.` : "";
1012
+ 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.";
992
1013
  const body = {
993
1014
  code: "PAYMENT_REQUIRED",
994
1015
  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.`,
@@ -997,10 +1018,19 @@ function buildPaymentRequired(opts) {
997
1018
  priceUsd: opts.priceUsd,
998
1019
  accepts,
999
1020
  comingSoon: !live,
1000
- alternatives: ["api_key_credits", "sample_mode"],
1001
- ...selfServe ? { selfServe } : {}
1021
+ alternatives: [
1022
+ ...creditsPayTo ? ["api_key_credits"] : [],
1023
+ ...opts.sampleMode ? ["sample_mode"] : []
1024
+ ],
1025
+ ...selfServe ? { selfServe } : {},
1026
+ ...opts.bazaar ? { extensions: { bazaar: opts.bazaar } } : {}
1002
1027
  };
1003
- const encoded = JSON.stringify({ x402Version: 2, accepts, resource: opts.resource });
1028
+ const encoded = JSON.stringify({
1029
+ x402Version: 2,
1030
+ accepts,
1031
+ resource: opts.resource,
1032
+ ...opts.bazaar ? { extensions: { bazaar: opts.bazaar } } : {}
1033
+ });
1004
1034
  const headers = {
1005
1035
  "Content-Type": "application/json",
1006
1036
  "WWW-Authenticate": `Payment realm="agentwares", methods="x402 prepaid_credits", price="${amountUsd} USD"`,
@@ -1021,7 +1051,7 @@ var StubVerifier = class {
1021
1051
  }
1022
1052
  };
1023
1053
 
1024
- // ../../packages/mcp-kit/dist/chunk-NF4BQXVM.js
1054
+ // ../../packages/mcp-kit/dist/chunk-7LRFDQNC.js
1025
1055
  import { z as z2 } from "zod";
1026
1056
  import { z as z3 } from "zod";
1027
1057
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
@@ -1493,21 +1523,26 @@ function withPayment(tool, opts) {
1493
1523
  if (auth.ok) return tool.handler(record, { ...ctx, userId: auth.userId });
1494
1524
  reason = auth.reason;
1495
1525
  }
1526
+ const resource = ctx.resourceUrl ?? tool.name;
1496
1527
  const required = buildPaymentRequired({
1497
- resource: tool.name,
1528
+ resource,
1498
1529
  priceUsd: opts.priceUsd,
1499
1530
  live: opts.live,
1500
1531
  description: opts.description,
1501
1532
  payTo: opts.payTo,
1502
1533
  creditsPayTo: opts.creditsPayTo,
1503
1534
  signupUrl: opts.signupUrl,
1504
- selfServe: opts.selfServe
1535
+ selfServe: opts.selfServe,
1536
+ // withPayment always adds a free `sample` flag to the tool's input schema
1537
+ sampleMode: true,
1538
+ ...opts.bazaar ? { bazaar: opts.bazaar } : {}
1505
1539
  });
1506
1540
  const advertised = required.body.accepts.find((a) => a.rail === "prepaid_credits") ?? required.body.accepts[0];
1507
1541
  const requirement = advertised ?? {
1508
1542
  rail: "prepaid_credits",
1509
1543
  amountUsd: String(required.body.priceUsd),
1510
- resource: tool.name
1544
+ resource,
1545
+ ...opts.description ? { description: opts.description } : {}
1511
1546
  };
1512
1547
  const verified = await verifier.verify(
1513
1548
  new Request(`https://mcp.local/${tool.name}`, { headers: ctx.headers }),
@@ -2740,6 +2775,7 @@ function readServers(file) {
2740
2775
  return servers;
2741
2776
  }
2742
2777
  var PROXY_SERVER_NAME = "agentguard";
2778
+ var PROXY_PACKAGE = "@agentwares/agentguard";
2743
2779
  function isProxyEntry(entry) {
2744
2780
  return (entry.args ?? []).some((a) => a === "agentguard" || /(^|\/)agentguard(\.js)?$/.test(a)) && (entry.args ?? []).includes("proxy");
2745
2781
  }
@@ -2783,7 +2819,7 @@ function backupPath(file) {
2783
2819
  return `${file.path}.agentguard-backup`;
2784
2820
  }
2785
2821
  function proxyEntry(file, policyPath, opts = {}) {
2786
- const args = ["-y", "agentguard", "proxy", "--config", policyPath];
2822
+ const args = ["-y", PROXY_PACKAGE, "proxy", "--config", policyPath];
2787
2823
  if (opts.agent) args.push("--agent", opts.agent);
2788
2824
  const entry = { command: "npx", args };
2789
2825
  if (file.serversKey === "servers") entry.type = "stdio";
@@ -3836,6 +3872,11 @@ async function initCommand(args, io) {
3836
3872
  }
3837
3873
  if (flagBool(args, "rewrite") !== false) {
3838
3874
  for (const c of chosen) {
3875
+ if (resolve3(c.path) === resolve3(policyPath)) {
3876
+ throw new Error(
3877
+ `refusing: ${rel(c.path)} is both the policy file (--config) and a client config. Rewriting it would replace the policy with the proxy entry and leave the proxy pointing at itself. Use --config for the policy path and --client for the client's config, or let --config default to agentguard.yaml.`
3878
+ );
3879
+ }
3839
3880
  const { backup, replaced } = rewriteClientConfig(c, policyPath, {
3840
3881
  agent: flagString(args, "agent")
3841
3882
  });