Skip to content

Commit a4ca90b

Browse files
Merge pull request #433 from basementstudio/canary
v0.5.8
2 parents 65e36a7 + c90d35c commit a4ca90b

34 files changed

+1258
-85
lines changed

examples/x402-http/.env.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Wallet address to receive USDC payments
2+
X402_WALLET=0xYOUR_WALLET_ADDRESS_HERE
3+
4+
# Optional: Custom facilitator URL (defaults to https://x402.org/facilitator)
5+
# X402_FACILITATOR=https://x402.org/facilitator

examples/x402-http/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.vercel
2+
.xmcp
3+
xmcp-env.d.ts
4+
.env

examples/x402-http/package.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"name": "paid-http-transport",
3+
"description": "Example of x402 paid tools with xmcp HTTP transport",
4+
"keywords": [
5+
"http",
6+
"x402",
7+
"paid"
8+
],
9+
"scripts": {
10+
"build": "xmcp build",
11+
"dev": "xmcp dev",
12+
"start": "node dist/http.js"
13+
},
14+
"dependencies": {
15+
"@xmcp-dev/x402": "workspace:*",
16+
"xmcp": "workspace:*",
17+
"zod": "^4.0.10"
18+
}
19+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { x402Provider } from "@xmcp-dev/x402";
2+
3+
export default x402Provider({
4+
wallet: process.env.X402_WALLET!,
5+
facilitator: process.env.X402_FACILITATOR ?? "https://x402.org/facilitator",
6+
debug: true,
7+
defaults: {
8+
price: 0.01,
9+
currency: "USDC",
10+
network: "base-sepolia",
11+
},
12+
});
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { z } from "zod";
2+
import { type InferSchema, type ToolMetadata } from "xmcp";
3+
import { paid } from "@xmcp-dev/x402";
4+
5+
// Define the schema for tool parameters
6+
export const schema = {
7+
name: z.string().describe("The name of the user to greet"),
8+
};
9+
10+
// Define tool metadata
11+
export const metadata: ToolMetadata = {
12+
name: "greet",
13+
description: "Greet the user (paid tool - $0.01)",
14+
annotations: {
15+
title: "Greet the user",
16+
readOnlyHint: true,
17+
destructiveHint: false,
18+
idempotentHint: true,
19+
},
20+
};
21+
22+
// Paid tool implementation - uses middleware defaults ($0.01)
23+
export default paid(async function greet({ name }: InferSchema<typeof schema>) {
24+
return `Hello, ${name}!! (paid by fran)`;
25+
});
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { z } from "zod";
2+
import { type InferSchema, type ToolMetadata } from "xmcp";
3+
import { paid } from "@xmcp-dev/x402";
4+
5+
export const schema = {
6+
input: z
7+
.string()
8+
.min(1, "Input string is required")
9+
.describe("The string to hash"),
10+
};
11+
12+
export const metadata: ToolMetadata = {
13+
name: "hash-string",
14+
description: "Hash a string using SHA-256 (paid tool - $0.05)",
15+
};
16+
17+
// Paid tool with custom price
18+
export default paid(
19+
{ price: 0.05 },
20+
async function hashString({ input }: InferSchema<typeof schema>) {
21+
if (!input || typeof input !== "string")
22+
return "Invalid input: string required";
23+
24+
// Use Web Crypto API for SHA-256 hashing
25+
async function sha256(str: string) {
26+
const encoder = new TextEncoder();
27+
const data = encoder.encode(str);
28+
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
29+
const hashArray = Array.from(new Uint8Array(hashBuffer));
30+
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
31+
}
32+
33+
const hash = await sha256(input);
34+
35+
return hash;
36+
}
37+
);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { ToolMetadata } from "xmcp";
2+
3+
export const metadata: ToolMetadata = {
4+
name: "random-number",
5+
description: "Generate a random number (free tool)",
6+
};
7+
8+
export default async function randomNumber() {
9+
const result = Math.random();
10+
11+
return result.toString();
12+
}

examples/x402-http/tsconfig.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2017",
4+
"module": "commonjs",
5+
"esModuleInterop": true,
6+
"forceConsistentCasingInFileNames": true,
7+
"strict": true,
8+
"skipLibCheck": true
9+
},
10+
"include": ["xmcp-env.d.ts", "src/**/*.ts"]
11+
}

examples/x402-http/xmcp.config.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { XmcpConfig } from "xmcp";
2+
3+
const config: XmcpConfig = {
4+
http: true,
5+
paths: {
6+
prompts: false,
7+
resources: false,
8+
},
9+
};
10+
11+
export default config;

packages/plugins/x402/README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# @xmcp-dev/x402
2+
3+
x402 payment protocol plugin for xmcp. Add paid tools with USDC on Base.
4+
5+
## Installation
6+
7+
```bash
8+
pnpm add @xmcp-dev/x402
9+
```
10+
11+
## Usage
12+
13+
### Middleware
14+
15+
```typescript
16+
// src/middleware.ts
17+
import { x402Middleware } from "@xmcp-dev/x402";
18+
19+
export default x402Middleware({
20+
wallet: process.env.X402_WALLET!,
21+
defaults: {
22+
price: 0.01,
23+
network: "base-sepolia",
24+
},
25+
});
26+
```
27+
28+
### Paid tools
29+
30+
```typescript
31+
// src/tools/my-tool.ts
32+
import { paid } from "@xmcp-dev/x402";
33+
34+
export default paid(async ({ input }) => {
35+
return { content: [{ type: "text", text: `Result: ${input}` }] };
36+
});
37+
```
38+
39+
```typescript
40+
// src/tools/premium-tool.ts
41+
import { paid } from "@xmcp-dev/x402";
42+
43+
export default paid({ price: 0.10 }, async ({ input }) => {
44+
return { content: [{ type: "text", text: `Premium: ${input}` }] };
45+
});
46+
```
47+
48+
### Payment context
49+
50+
```typescript
51+
import { paid, payment } from "@xmcp-dev/x402";
52+
53+
export default paid(async ({ input }) => {
54+
const { payer, amount, network } = payment();
55+
return { content: [{ type: "text", text: `Paid by ${payer}` }] };
56+
});
57+
```
58+
59+
## API
60+
61+
### `x402Middleware(config)`
62+
63+
```typescript
64+
interface X402Config {
65+
wallet: string;
66+
facilitator?: string;
67+
debug?: boolean;
68+
defaults?: {
69+
price?: number;
70+
currency?: string;
71+
network?: string;
72+
maxPaymentAge?: number;
73+
};
74+
}
75+
```
76+
77+
### `paid(options?, handler)`
78+
79+
```typescript
80+
interface X402ToolOptions {
81+
price?: number;
82+
currency?: string;
83+
network?: string;
84+
maxPaymentAge?: number;
85+
description?: string;
86+
}
87+
```
88+
89+
### `payment()`
90+
91+
```typescript
92+
interface X402PaymentContext {
93+
payer: string;
94+
amount: string;
95+
network: string;
96+
asset: string;
97+
toolName: string;
98+
transactionHash?: string;
99+
}
100+
```
101+
102+
## Networks
103+
104+
| Network | USDC Address |
105+
|---------|--------------|
106+
| `base` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
107+
| `base-sepolia` | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` |
108+
109+
## License
110+
111+
MIT

0 commit comments

Comments
 (0)