@crawlpay/mcp-server 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 ADDED
@@ -0,0 +1,60 @@
1
+ # @crawlpay/mcp-server
2
+
3
+ CrawlPay MCP server for Claude Desktop, Cursor, Windsurf.
4
+
5
+ Automatically pays $0.001 USDC per page when an AI agent
6
+ encounters a CrawlPay-protected paywall.
7
+
8
+ ## Setup
9
+
10
+ Add to your Claude Desktop config:
11
+
12
+ ```json
13
+ {
14
+ "mcpServers": {
15
+ "crawlpay-server": {
16
+ "command": "npx",
17
+ "args": ["-y", "@crawlpay/mcp-server"],
18
+ "env": {
19
+ "CRAWLPAY_API_KEY": "cr_live_YOUR_KEY_HERE"
20
+ }
21
+ }
22
+ }
23
+ }
24
+ ```
25
+
26
+ Config file location:
27
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
28
+ - Mac: `~/Library/Application Support/Claude/claude_desktop_config.json`
29
+
30
+ ## Get API key
31
+
32
+ 1. Go to crawl-pay.com/connect/api-keys
33
+ 2. Sign in with Google or GitHub
34
+ 3. Fund your wallet with USDC on Base
35
+ 4. Generate API key
36
+ 5. Paste it into config above
37
+
38
+ ## Tool
39
+
40
+ `handle_payment_required`
41
+ - url: URL that returned 402
42
+ - amount: USDC amount (default "0.001")
43
+
44
+ ## How it works
45
+
46
+ ```
47
+ Agent reads a CrawlPay-protected page
48
+ → Gets HTTP 402 Payment Required
49
+ → MCP server intercepts
50
+ → Pays $0.001 USDC on Base automatically
51
+ → Content unlocked
52
+ ```
53
+
54
+ ## Links
55
+
56
+ - [crawl-pay.com](https://crawl-pay.com)
57
+ - [github.com/divergenttt/CrawlPay-Vault](https://github.com/divergenttt/CrawlPay-Vault)
58
+ - npm: coming soon
59
+
60
+ *Built on Base · Circle · Privy*
package/crawlpay.md ADDED
@@ -0,0 +1,31 @@
1
+ # CrawlPay Plugin
2
+
3
+ ## Description
4
+ CrawlPay enables AI agents to automatically pay for paywalled web content
5
+ using USDC on Base. When an agent encounters HTTP 402 Payment Required,
6
+ this plugin handles the payment flow automatically.
7
+
8
+ ## Tools
9
+
10
+ ### handle_payment_required
11
+ Handles HTTP 402 responses from CrawlPay-protected pages.
12
+
13
+ **When to use:** Call this tool whenever you receive a 402 Payment Required
14
+ error while trying to read a webpage. The site is protected by CrawlPay
15
+ and requires $0.001 USDC payment per page.
16
+
17
+ **Inputs:**
18
+ - url: The URL that returned 402
19
+ - amount: Payment amount in USDC (usually "0.001")
20
+
21
+ **Flow:**
22
+ 1. If CRAWLPAY_API_KEY is set: pays automatically via API key, returns content
23
+ 2. If no API key: returns Base MCP approval link for manual payment
24
+
25
+ ## Setup
26
+ Set CRAWLPAY_API_KEY=cr_live_... in your environment for automatic payments.
27
+ Get your API key at https://crawl-pay.com/connect/api-keys
28
+
29
+ ## Example
30
+ User: "Read this article: example.com/premium/article"
31
+ Agent: fetches URL → gets 402 → calls handle_payment_required → pays → returns content
@@ -0,0 +1,3 @@
1
+ export declare function resolveCrawlPayApiKey(): string | undefined;
2
+ export declare function buildAgentHeaders(base?: Record<string, string>): Record<string, string>;
3
+ export declare function fetchPaidPage(url: string): Promise<Response>;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveCrawlPayApiKey = resolveCrawlPayApiKey;
4
+ exports.buildAgentHeaders = buildAgentHeaders;
5
+ exports.fetchPaidPage = fetchPaidPage;
6
+ function resolveCrawlPayApiKey() {
7
+ const key = process.env.CRAWLPAY_API_KEY?.trim() ||
8
+ process.env.CRAWLPAY_AGENT_API_KEY?.trim();
9
+ return key?.startsWith("cr_live_") ? key : undefined;
10
+ }
11
+ function buildAgentHeaders(base = {}) {
12
+ const headers = {
13
+ "User-Agent": process.env.CRAWLPAY_BOT_USER_AGENT ??
14
+ "GPTBot (CrawlPay-MCP/1.0)",
15
+ ...base,
16
+ };
17
+ const apiKey = resolveCrawlPayApiKey();
18
+ if (apiKey) {
19
+ headers.Authorization = `Bearer ${apiKey}`;
20
+ }
21
+ return headers;
22
+ }
23
+ async function fetchPaidPage(url) {
24
+ const apiKey = resolveCrawlPayApiKey();
25
+ const first = await fetch(url, {
26
+ headers: buildAgentHeaders(),
27
+ cache: "no-store",
28
+ });
29
+ if (apiKey || first.status !== 402) {
30
+ return first;
31
+ }
32
+ const botAddress = process.env.NEXT_PUBLIC_SELLER_ADDRESS?.trim() ?? "";
33
+ return fetch(url, {
34
+ headers: {
35
+ ...buildAgentHeaders(),
36
+ "payment-signature": "0xsimulated",
37
+ "payment-bot-address": botAddress,
38
+ ...(first.headers.get("x-crawlpay-vault")
39
+ ? { "x-crawlpay-vault": first.headers.get("x-crawlpay-vault") }
40
+ : {}),
41
+ },
42
+ cache: "no-store",
43
+ });
44
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,124 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
5
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
7
+ const viem_1 = require("viem");
8
+ const crawlpay_fetch_1 = require("./crawlpay-fetch");
9
+ const TOOL_NAME = "handle_payment_required";
10
+ const server = new index_js_1.Server({
11
+ name: "crawlpay-server",
12
+ version: "0.1.0",
13
+ }, {
14
+ capabilities: {
15
+ tools: {},
16
+ },
17
+ });
18
+ const SELLER_ADDRESS = process.env.NEXT_PUBLIC_SELLER_ADDRESS?.trim() ||
19
+ process.env.SELLER_ADDRESS?.trim() ||
20
+ "0x80B6173DD42a787BbFF2B2617652885a3dE9b05B"; // CrawlPay default
21
+ /** Base App deep link — triggers USDC transfer via wallet_sendCalls flow. */
22
+ function buildApprovalLink(amount) {
23
+ const params = new URLSearchParams({
24
+ to: SELLER_ADDRESS,
25
+ amount,
26
+ token: "USDC",
27
+ chainId: "8453",
28
+ });
29
+ return `https://www.base.org/send?${params.toString()}`;
30
+ }
31
+ function validateArgs(args) {
32
+ if (!args || typeof args !== "object") {
33
+ throw new Error("Invalid arguments: object expected");
34
+ }
35
+ const { url, amount } = args;
36
+ if (typeof url !== "string" || url.trim().length === 0) {
37
+ throw new Error("Invalid arguments: `url` must be a non-empty string");
38
+ }
39
+ if (typeof amount !== "string" || amount.trim().length === 0) {
40
+ throw new Error("Invalid arguments: `amount` must be a non-empty string");
41
+ }
42
+ // Validate numeric amount format in USDC precision.
43
+ (0, viem_1.parseUnits)(amount, 6);
44
+ return { url: url.trim(), amount: amount.trim() };
45
+ }
46
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
47
+ console.error("[crawlpay-mcp] Listing tools");
48
+ return {
49
+ tools: [
50
+ {
51
+ name: TOOL_NAME,
52
+ description: "Handle HTTP 402 Payment Required from CrawlPay-protected pages. " +
53
+ "Call when a webpage returns 402 — pays automatically if CRAWLPAY_API_KEY is set, " +
54
+ "otherwise returns a Base App USDC approval link.",
55
+ inputSchema: {
56
+ type: "object",
57
+ properties: {
58
+ url: {
59
+ type: "string",
60
+ description: "URL of the protected page/resource that returned 402",
61
+ },
62
+ amount: {
63
+ type: "string",
64
+ description: 'Requested USDC amount (example: "0.001")',
65
+ },
66
+ },
67
+ required: ["url", "amount"],
68
+ additionalProperties: false,
69
+ },
70
+ },
71
+ ],
72
+ };
73
+ });
74
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
75
+ const { name, arguments: args } = request.params;
76
+ console.error(`[crawlpay-mcp] Tool call received: ${name}`);
77
+ if (name !== TOOL_NAME) {
78
+ throw new Error(`Unknown tool: ${name}`);
79
+ }
80
+ const { url, amount } = validateArgs(args);
81
+ console.error(`[crawlpay-mcp] 402 context parsed. url=${url} amount=${amount}`);
82
+ const apiKey = (0, crawlpay_fetch_1.resolveCrawlPayApiKey)();
83
+ if (apiKey) {
84
+ console.error("[crawlpay-mcp] Retrying with CrawlPay API key (Base wallet)");
85
+ const res = await (0, crawlpay_fetch_1.fetchPaidPage)(url);
86
+ const body = await res.text();
87
+ return {
88
+ content: [
89
+ {
90
+ type: "text",
91
+ text: `CrawlPay fetch (${res.status})\n` +
92
+ `URL: ${url}\n` +
93
+ `Amount: ${amount} USDC\n` +
94
+ `Auth: API key (cr_live_…)\n\n` +
95
+ body.slice(0, 4000),
96
+ },
97
+ ],
98
+ };
99
+ }
100
+ const approvalLink = buildApprovalLink(amount);
101
+ console.error("[crawlpay-mcp] No API key — returning Base App approval link");
102
+ return {
103
+ content: [
104
+ {
105
+ type: "text",
106
+ text: "Payment required — set CRAWLPAY_API_KEY=cr_live_… for automatic Base wallet billing,\n" +
107
+ "or approve USDC payment via Base App:\n\n" +
108
+ `Protected URL: ${url}\n` +
109
+ `Amount: ${amount} USDC\n` +
110
+ `Base approval link: ${approvalLink}`,
111
+ },
112
+ ],
113
+ };
114
+ });
115
+ async function main() {
116
+ console.error("[crawlpay-mcp] Starting stdio server...");
117
+ const transport = new stdio_js_1.StdioServerTransport();
118
+ await server.connect(transport);
119
+ console.error("[crawlpay-mcp] Server connected on stdio");
120
+ }
121
+ main().catch((error) => {
122
+ console.error("[crawlpay-mcp] Fatal startup error:", error);
123
+ process.exit(1);
124
+ });
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@crawlpay/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "Official CrawlPay MCP server for payment-required (402) flows",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/divergenttt/CrawlPay-MCP"
8
+ },
9
+ "homepage": "https://crawl-pay.com",
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "bin": {
13
+ "crawlpay-mcp": "dist/index.js"
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "crawlpay.md"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc -p tsconfig.json",
21
+ "dev": "ts-node src/index.ts",
22
+ "start": "node dist/index.js"
23
+ },
24
+ "dependencies": {
25
+ "@modelcontextprotocol/sdk": "^1.29.0",
26
+ "viem": "^2.50.4"
27
+ },
28
+ "devDependencies": {
29
+ "@types/node": "^24.12.4",
30
+ "ts-node": "^10.9.2",
31
+ "typescript": "^5.9.3"
32
+ },
33
+ "license": "MIT",
34
+ "keywords": [
35
+ "mcp",
36
+ "crawlpay",
37
+ "x402",
38
+ "base",
39
+ "usdc",
40
+ "ai-agents"
41
+ ]
42
+ }