@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 +93 -2
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +7 -0
- package/dist/cli.js.map +1 -0
- package/dist/evaluate.d.ts +38 -0
- package/dist/evaluate.d.ts.map +1 -0
- package/dist/evaluate.js +154 -0
- package/dist/evaluate.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/normalize.d.ts +4 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +88 -0
- package/dist/normalize.js.map +1 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +50 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -4
- package/server.json +31 -0
package/README.md
CHANGED
|
@@ -1,3 +1,94 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @paystage/preflight
|
|
2
2
|
|
|
3
|
-
|
|
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 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
package/dist/cli.js.map
ADDED
|
@@ -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"}
|
package/dist/evaluate.js
ADDED
|
@@ -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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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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 @@
|
|
|
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 @@
|
|
|
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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"}
|
package/dist/server.d.ts
ADDED
|
@@ -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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
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
|
+
}
|