@paystage/preflight 0.0.0-stage → 0.1.0

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 CHANGED
@@ -1,3 +1,94 @@
1
- # Temporary Holding Version
1
+ # @paystage/preflight
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Evaluate an [x402](https://x402.org) `PaymentRequired` against a local spending
4
+ policy **before** your agent pays. Returns one of three verdicts: `pay`,
5
+ `review`, or `do_not_pay`.
6
+
7
+ - **Local-first** — policy lives in a JSON file on your machine. No secrets, no
8
+ network calls to decide.
9
+ - **MCP-native** — runs as a stdio MCP server so Claude Desktop, Cursor, and any
10
+ MCP client can call it as a tool.
11
+ - **Deterministic** — same input + same policy ⇒ same verdict.
12
+
13
+ ## Install
14
+
15
+ Run directly with `npx` (no global install):
16
+
17
+ ```bash
18
+ npx -y @paystage/preflight
19
+ ```
20
+
21
+ Or add it to your MCP client config.
22
+
23
+ ## Claude Desktop
24
+
25
+ Add to `claude_desktop_config.json`:
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "paystage-preflight": {
31
+ "command": "npx",
32
+ "args": ["-y", "@paystage/preflight"],
33
+ "env": {
34
+ "PAYSTAGE_POLICY_PATH": "/absolute/path/to/policy.json"
35
+ }
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ ## Cursor
42
+
43
+ Add to `.cursor/mcp.json`:
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "paystage-preflight": {
49
+ "command": "npx",
50
+ "args": ["-y", "@paystage/preflight"],
51
+ "env": {
52
+ "PAYSTAGE_POLICY_PATH": "/absolute/path/to/policy.json"
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ ## Example `policy.json`
60
+
61
+ ```json
62
+ {
63
+ "version": 1,
64
+ "name": "standard",
65
+ "allowed_networks": ["eip155:8453", "eip155:84532"],
66
+ "allowed_assets": [
67
+ "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
68
+ "0x036CbD53842c5426634e7929541eC2318f3dCF7e"
69
+ ],
70
+ "allowed_pay_to": ["0x209693Bc6afc0C5328bA36FaF03C514EF312287C"],
71
+ "max_amount_per_call": "1.00",
72
+ "max_amount_per_session": "10.00",
73
+ "require_human_above": "0.50",
74
+ "max_timeout_seconds": 300,
75
+ "default_verdict": "review"
76
+ }
77
+ ```
78
+
79
+ Amounts are human-readable USDC (e.g. `"0.50"` = 0.50 USDC). Networks use
80
+ CAIP-2 identifiers.
81
+
82
+ ## Verdicts
83
+
84
+ | Verdict | Meaning |
85
+ | ------------- | ----------------------------------------------------------------------- |
86
+ | `pay` | Within policy — safe to proceed automatically. |
87
+ | `review` | Allowed but above a human threshold — ask a human before paying. |
88
+ | `do_not_pay` | Violates policy (network, asset, payTo, amount, timeout, or malformed). |
89
+
90
+ ## Links
91
+
92
+ - Website: <https://paystage.xyz>
93
+ - Source: <https://github.com/base-buzz/paystage>
94
+ - License: MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { startServer } from "./server.js";
3
+ startServer().catch((error) => {
4
+ console.error(error);
5
+ process.exit(1);
6
+ });
7
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IACrC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { type Policy } from "@paystage/policy";
2
+ export interface AcceptOption {
3
+ scheme: string;
4
+ network: string;
5
+ amount: string;
6
+ asset: string;
7
+ payTo: string;
8
+ maxTimeoutSeconds: number;
9
+ extra?: Record<string, unknown>;
10
+ }
11
+ export interface PaymentResource {
12
+ url: string;
13
+ description?: string;
14
+ mimeType?: string;
15
+ }
16
+ export interface PaymentRequest {
17
+ x402Version: number;
18
+ accepts: AcceptOption[];
19
+ error?: string;
20
+ resource?: PaymentResource;
21
+ }
22
+ export type Decision = "pay" | "review" | "do_not_pay";
23
+ export type AcceptStatus = "pay" | "review" | "do_not_pay";
24
+ export interface AcceptResult {
25
+ accept: AcceptOption;
26
+ status: AcceptStatus;
27
+ reasons: string[];
28
+ }
29
+ export interface EvaluateResult {
30
+ decision: Decision;
31
+ selectedAccept?: AcceptOption;
32
+ acceptResults: AcceptResult[];
33
+ reasons: string[];
34
+ summary: string;
35
+ dailyCapNote?: string;
36
+ }
37
+ export declare function evaluatePayment(pr: PaymentRequest, policy: Policy): EvaluateResult;
38
+ //# sourceMappingURL=evaluate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../src/evaluate.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,MAAM,EAEZ,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,eAAe,CAAC;CAC5B;AAED,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,YAAY,CAAC;AACvD,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE3D,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,QAAQ,CAAC;IACnB,cAAc,CAAC,EAAE,YAAY,CAAC;IAC9B,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAmHD,wBAAgB,eAAe,CAC7B,EAAE,EAAE,cAAc,EAClB,MAAM,EAAE,MAAM,GACb,cAAc,CA2EhB"}
@@ -0,0 +1,154 @@
1
+ import { humanToAtomic, atomicToHuman, } from "@paystage/policy";
2
+ function eq(a, b) {
3
+ return a.toLowerCase() === b.toLowerCase();
4
+ }
5
+ function findAsset(policy, network, assetAddress) {
6
+ return policy.allowed_assets.find((a) => eq(a.network, network) && eq(a.address, assetAddress));
7
+ }
8
+ function evaluateAccept(accept, policy) {
9
+ const reasons = [];
10
+ // Rule 2: network allowlist
11
+ const networkAllowed = policy.allowed_networks.some((n) => eq(n, accept.network));
12
+ if (!networkAllowed) {
13
+ reasons.push(`network ${accept.network} not in allowed_networks`);
14
+ return { accept, status: "do_not_pay", reasons };
15
+ }
16
+ // Rule 3: asset must match allowed_assets with same network
17
+ const asset = findAsset(policy, accept.network, accept.asset);
18
+ if (!asset) {
19
+ reasons.push(`asset ${accept.asset} on ${accept.network} not in allowed_assets`);
20
+ return { accept, status: "do_not_pay", reasons };
21
+ }
22
+ // Rule 4: amount is atomic
23
+ let amount;
24
+ try {
25
+ amount = BigInt(accept.amount);
26
+ }
27
+ catch {
28
+ reasons.push(`invalid atomic amount ${accept.amount}`);
29
+ return { accept, status: "do_not_pay", reasons };
30
+ }
31
+ // Rule 5: policy-level max_amount, only if asset symbol matches
32
+ if (eq(policy.max_amount.asset, asset.symbol)) {
33
+ const maxAtomic = humanToAtomic(policy.max_amount.value, policy.max_amount.decimals);
34
+ if (amount > maxAtomic) {
35
+ reasons.push(`amount ${atomicToHuman(amount, asset.decimals)} ${asset.symbol} exceeds max_amount ${policy.max_amount.value} ${policy.max_amount.asset}`);
36
+ return { accept, status: "do_not_pay", reasons };
37
+ }
38
+ }
39
+ // Rule 6: timeout
40
+ if (accept.maxTimeoutSeconds > policy.max_timeout_seconds) {
41
+ reasons.push(`maxTimeoutSeconds ${accept.maxTimeoutSeconds} exceeds policy max_timeout_seconds ${policy.max_timeout_seconds}`);
42
+ return { accept, status: "do_not_pay", reasons };
43
+ }
44
+ // Rule 7: payee allowlist
45
+ const payeeAllowed = policy.allowed_pay_to.some((p) => eq(p, accept.payTo));
46
+ if (!payeeAllowed) {
47
+ if (policy.unknown_payee === "deny") {
48
+ reasons.push(`payTo ${accept.payTo} not in allowed_pay_to (deny)`);
49
+ return { accept, status: "do_not_pay", reasons };
50
+ }
51
+ reasons.push(`payTo ${accept.payTo} not in allowed_pay_to (review)`);
52
+ return { accept, status: "review", reasons };
53
+ }
54
+ // Rule 8: require_human_above
55
+ if (policy.require_human_above) {
56
+ const threshold = humanToAtomic(policy.require_human_above.value, policy.require_human_above.decimals);
57
+ if (amount > threshold) {
58
+ reasons.push(`amount ${atomicToHuman(amount, asset.decimals)} ${asset.symbol} exceeds require_human_above ${policy.require_human_above.value} ${policy.require_human_above.asset}`);
59
+ return { accept, status: "review", reasons };
60
+ }
61
+ }
62
+ return { accept, status: "pay", reasons };
63
+ }
64
+ function amountOf(accept) {
65
+ try {
66
+ return BigInt(accept.amount);
67
+ }
68
+ catch {
69
+ return BigInt(0);
70
+ }
71
+ }
72
+ function cheapest(accepts) {
73
+ if (accepts.length === 0)
74
+ return undefined;
75
+ return [...accepts].sort((a, b) => {
76
+ const da = amountOf(a);
77
+ const db = amountOf(b);
78
+ if (da < db)
79
+ return -1;
80
+ if (da > db)
81
+ return 1;
82
+ return a.maxTimeoutSeconds - b.maxTimeoutSeconds;
83
+ })[0];
84
+ }
85
+ export function evaluatePayment(pr, policy) {
86
+ // Rule 1: malformed
87
+ if (!pr || pr.x402Version !== 2) {
88
+ return {
89
+ decision: "do_not_pay",
90
+ acceptResults: [],
91
+ reasons: [`unsupported x402Version ${pr?.x402Version}`],
92
+ summary: "Payment request is malformed or unsupported version.",
93
+ };
94
+ }
95
+ if (!Array.isArray(pr.accepts) || pr.accepts.length === 0) {
96
+ return {
97
+ decision: "do_not_pay",
98
+ acceptResults: [],
99
+ reasons: ["no accepts in payment request"],
100
+ summary: "Payment request has no acceptable payment options.",
101
+ };
102
+ }
103
+ const acceptResults = pr.accepts.map((a) => evaluateAccept(a, policy));
104
+ const payAccepts = acceptResults
105
+ .filter((r) => r.status === "pay")
106
+ .map((r) => r.accept);
107
+ const reviewAccepts = acceptResults
108
+ .filter((r) => r.status === "review")
109
+ .map((r) => r.accept);
110
+ let decision;
111
+ let selectedAccept;
112
+ if (payAccepts.length > 0) {
113
+ decision = "pay";
114
+ selectedAccept = cheapest(payAccepts);
115
+ }
116
+ else if (reviewAccepts.length > 0) {
117
+ decision = "review";
118
+ selectedAccept = cheapest(reviewAccepts);
119
+ }
120
+ else {
121
+ decision = "do_not_pay";
122
+ }
123
+ const reasons = [];
124
+ for (const r of acceptResults) {
125
+ for (const reason of r.reasons)
126
+ reasons.push(reason);
127
+ }
128
+ // Rule 9: daily_cap note only
129
+ let dailyCapNote;
130
+ if (policy.daily_cap) {
131
+ dailyCapNote = `daily_cap ${policy.daily_cap.value} ${policy.daily_cap.asset} (informational only)`;
132
+ }
133
+ // Rule 12: summary
134
+ let summary;
135
+ if (selectedAccept) {
136
+ const asset = findAsset(policy, selectedAccept.network, selectedAccept.asset);
137
+ const decimals = asset?.decimals ?? policy.max_amount.decimals;
138
+ const human = atomicToHuman(BigInt(selectedAccept.amount), decimals);
139
+ const symbol = asset?.symbol ?? policy.max_amount.asset;
140
+ summary = `Decision: ${decision}. Selected ${human} ${symbol} on ${selectedAccept.network} to ${selectedAccept.payTo}.`;
141
+ }
142
+ else {
143
+ summary = `Decision: ${decision}. No acceptable payment option.`;
144
+ }
145
+ return {
146
+ decision,
147
+ selectedAccept,
148
+ acceptResults,
149
+ reasons,
150
+ summary,
151
+ dailyCapNote,
152
+ };
153
+ }
154
+ //# sourceMappingURL=evaluate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../src/evaluate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { evaluatePayment } from "./evaluate.js";
2
+ export type { AcceptOption, PaymentResource, PaymentRequest, Decision, AcceptStatus, AcceptResult, EvaluateResult, } from "./evaluate.js";
3
+ export { normalizePaymentRequired } from "./normalize.js";
4
+ export { createServer, startServer } from "./server.js";
5
+ export type { PaymentRequired, PaymentAccept, EvaluationResult, EvaluationDecision, AcceptEvaluation, } from "./types.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACxD,YAAY,EACV,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { evaluatePayment } from "./evaluate.js";
2
+ export { normalizePaymentRequired } from "./normalize.js";
3
+ export { createServer, startServer } from "./server.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAUhD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,4 @@
1
+ export type { PaymentRequest, AcceptOption, PaymentResource, } from "./evaluate.js";
2
+ import type { PaymentRequest } from "./evaluate.js";
3
+ export declare function normalizePaymentRequired(input: unknown): PaymentRequest;
4
+ //# sourceMappingURL=normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,cAAc,EACd,YAAY,EACZ,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EACV,cAAc,EAGf,MAAM,eAAe,CAAC;AA6EvB,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAsBvE"}
@@ -0,0 +1,88 @@
1
+ function isRecord(value) {
2
+ return typeof value === "object" && value !== null;
3
+ }
4
+ function parseJsonText(text) {
5
+ try {
6
+ return JSON.parse(text);
7
+ }
8
+ catch {
9
+ throw new Error("content text is not valid JSON");
10
+ }
11
+ }
12
+ function coerceResource(raw) {
13
+ if (!isRecord(raw))
14
+ return undefined;
15
+ if (typeof raw.url !== "string")
16
+ return undefined;
17
+ return {
18
+ url: raw.url,
19
+ description: typeof raw.description === "string" ? raw.description : undefined,
20
+ mimeType: typeof raw.mimeType === "string" ? raw.mimeType : undefined,
21
+ };
22
+ }
23
+ function coerceAccept(raw) {
24
+ const amount = typeof raw.amount === "string"
25
+ ? raw.amount
26
+ : typeof raw.maxAmountRequired === "string"
27
+ ? raw.maxAmountRequired
28
+ : undefined;
29
+ if (typeof raw.scheme !== "string" ||
30
+ typeof raw.network !== "string" ||
31
+ typeof amount !== "string" ||
32
+ typeof raw.asset !== "string" ||
33
+ typeof raw.payTo !== "string" ||
34
+ typeof raw.maxTimeoutSeconds !== "number") {
35
+ throw new Error("malformed accept option");
36
+ }
37
+ return {
38
+ scheme: raw.scheme,
39
+ network: raw.network,
40
+ amount,
41
+ asset: raw.asset,
42
+ payTo: raw.payTo,
43
+ maxTimeoutSeconds: raw.maxTimeoutSeconds,
44
+ extra: isRecord(raw.extra) ? raw.extra : undefined,
45
+ };
46
+ }
47
+ function coercePaymentRequired(candidate) {
48
+ if (!isRecord(candidate)) {
49
+ throw new Error("PaymentRequired must be an object");
50
+ }
51
+ if (candidate.x402Version !== 2) {
52
+ throw new Error(`x402Version must be 2, got ${String(candidate.x402Version)}`);
53
+ }
54
+ if (!Array.isArray(candidate.accepts)) {
55
+ throw new Error("accepts must be an array");
56
+ }
57
+ const accepts = candidate.accepts.map((item, i) => {
58
+ if (!isRecord(item))
59
+ throw new Error(`accepts[${i}] must be an object`);
60
+ return coerceAccept(item);
61
+ });
62
+ return {
63
+ x402Version: 2,
64
+ accepts,
65
+ error: typeof candidate.error === "string" ? candidate.error : undefined,
66
+ resource: coerceResource(candidate.resource),
67
+ };
68
+ }
69
+ export function normalizePaymentRequired(input) {
70
+ if (!isRecord(input)) {
71
+ throw new Error("payment required input must be an object");
72
+ }
73
+ if ("x402Version" in input && "accepts" in input) {
74
+ return coercePaymentRequired(input);
75
+ }
76
+ if ("structuredContent" in input) {
77
+ return coercePaymentRequired(input.structuredContent);
78
+ }
79
+ if (Array.isArray(input.content)) {
80
+ const textItem = input.content.find((c) => isRecord(c) && c.type === "text" && typeof c.text === "string");
81
+ if (!textItem || !isRecord(textItem) || typeof textItem.text !== "string") {
82
+ throw new Error("MCP tool result content array did not include a text JSON payload");
83
+ }
84
+ return coercePaymentRequired(parseJsonText(textItem.text));
85
+ }
86
+ throw new Error("Unrecognized PaymentRequired input shape");
87
+ }
88
+ //# sourceMappingURL=normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../src/normalize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createServer(): McpServer;
3
+ export declare function startServer(): Promise<void>;
4
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASpE,wBAAgB,YAAY,IAAI,SAAS,CA2CxC;AAcD,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAIjD"}
package/dist/server.js ADDED
@@ -0,0 +1,50 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { z } from "zod";
4
+ import { loadPolicy, parsePolicy } from "@paystage/policy";
5
+ import { normalizePaymentRequired } from "./normalize.js";
6
+ import { evaluatePayment } from "./evaluate.js";
7
+ export function createServer() {
8
+ const server = new McpServer({
9
+ name: "paystage-preflight",
10
+ version: "0.1.0",
11
+ });
12
+ server.registerTool("evaluate_mcp_payment", {
13
+ description: "Evaluate an x402 PaymentRequired payload against a PayStage spending policy before paying",
14
+ inputSchema: {
15
+ payment_required: z.unknown(),
16
+ policy_path: z.string().optional(),
17
+ policy: z.unknown().optional(),
18
+ },
19
+ }, async (input) => {
20
+ try {
21
+ const policy = await resolvePolicy(input);
22
+ const pr = normalizePaymentRequired(input.payment_required);
23
+ const result = evaluatePayment(pr, policy);
24
+ return {
25
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
26
+ };
27
+ }
28
+ catch (error) {
29
+ const message = error instanceof Error ? error.message : String(error);
30
+ return {
31
+ isError: true,
32
+ content: [{ type: "text", text: `Error: ${message}` }],
33
+ };
34
+ }
35
+ });
36
+ return server;
37
+ }
38
+ async function resolvePolicy(input) {
39
+ if (input.policy !== undefined) {
40
+ return parsePolicy(input.policy);
41
+ }
42
+ const path = input.policy_path ?? process.env.PAYSTAGE_POLICY_PATH ?? "./policy.json";
43
+ return await loadPolicy(path);
44
+ }
45
+ export async function startServer() {
46
+ const server = createServer();
47
+ const transport = new StdioServerTransport();
48
+ await server.connect(transport);
49
+ }
50
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGhD,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,MAAM,CAAC,YAAY,CACjB,sBAAsB,EACtB;QACE,WAAW,EACT,2FAA2F;QAC7F,WAAW,EAAE;YACX,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE;YAC7B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAClC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;SAC/B;KACF,EACD,KAAK,EAAE,KAIN,EAGE,EAAE;QACH,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;YAC1C,MAAM,EAAE,GAAG,wBAAwB,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;YAC5D,MAAM,MAAM,GAAmB,eAAe,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;YAC3D,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;aACnE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC;aACvD,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,KAG5B;IACC,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,IAAI,GACR,KAAK,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,eAAe,CAAC;IAC3E,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export type { AcceptOption, PaymentResource, PaymentRequest, Decision, AcceptStatus, AcceptResult, EvaluateResult, } from "./evaluate.js";
2
+ /** @deprecated alias */
3
+ export type PaymentRequired = import("./evaluate.js").PaymentRequest;
4
+ export type PaymentAccept = import("./evaluate.js").AcceptOption;
5
+ export type EvaluationResult = import("./evaluate.js").EvaluateResult;
6
+ export type EvaluationDecision = import("./evaluate.js").Decision;
7
+ export type AcceptEvaluation = import("./evaluate.js").AcceptResult;
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,eAAe,EACf,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,cAAc,GACf,MAAM,eAAe,CAAC;AAEvB,wBAAwB;AACxB,MAAM,MAAM,eAAe,GAAG,OAAO,eAAe,EAAE,cAAc,CAAC;AACrE,MAAM,MAAM,aAAa,GAAG,OAAO,eAAe,EAAE,YAAY,CAAC;AACjE,MAAM,MAAM,gBAAgB,GAAG,OAAO,eAAe,EAAE,cAAc,CAAC;AACtE,MAAM,MAAM,kBAAkB,GAAG,OAAO,eAAe,EAAE,QAAQ,CAAC;AAClE,MAAM,MAAM,gBAAgB,GAAG,OAAO,eAAe,EAAE,YAAY,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,63 @@
1
1
  {
2
2
  "name": "@paystage/preflight",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Evaluate x402 PaymentRequired against a local spending policy before an agent pays",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js"
13
+ }
14
+ },
15
+ "bin": {
16
+ "paystage-preflight": "./dist/cli.js"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "server.json"
21
+ ],
22
+ "mcpName": "xyz.paystage/preflight",
23
+ "engines": {
24
+ "node": ">=20"
25
+ },
26
+ "keywords": [
27
+ "mcp",
28
+ "x402",
29
+ "agent-payments",
30
+ "usdc",
31
+ "base",
32
+ "preflight",
33
+ "policy"
34
+ ],
35
+ "homepage": "https://paystage.xyz",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/base-buzz/paystage.git",
39
+ "directory": "packages/preflight"
40
+ },
41
+ "bugs": {
42
+ "url": "https://github.com/base-buzz/paystage/issues"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc",
49
+ "test": "vitest run",
50
+ "typecheck": "tsc --noEmit",
51
+ "prepublishOnly": "npm run typecheck && npm run build"
52
+ },
53
+ "dependencies": {
54
+ "@modelcontextprotocol/sdk": "^1.12.0",
55
+ "@paystage/policy": "0.1.0",
56
+ "zod": "^3.23.8"
57
+ },
58
+ "devDependencies": {
59
+ "@types/node": "^20.14.0",
60
+ "typescript": "^5.5.4",
61
+ "vitest": "^2.0.5"
62
+ }
63
+ }
package/server.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "xyz.paystage/preflight",
4
+ "title": "PayStage Preflight",
5
+ "description": "Evaluate x402 PaymentRequired against a local spending policy before an agent pays",
6
+ "version": "0.1.0",
7
+ "websiteUrl": "https://paystage.xyz",
8
+ "repository": {
9
+ "url": "https://github.com/base-buzz/paystage",
10
+ "source": "github",
11
+ "subfolder": "packages/preflight"
12
+ },
13
+ "packages": [
14
+ {
15
+ "registryType": "npm",
16
+ "registryBaseUrl": "https://registry.npmjs.org",
17
+ "identifier": "@paystage/preflight",
18
+ "version": "0.1.0",
19
+ "transport": {
20
+ "type": "stdio"
21
+ },
22
+ "environmentVariables": [
23
+ {
24
+ "name": "PAYSTAGE_POLICY_PATH",
25
+ "description": "Path to policy.json spending rules",
26
+ "isRequired": false
27
+ }
28
+ ]
29
+ }
30
+ ]
31
+ }