skim-mcp 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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +137 -0
  3. package/dist/index.js +102 -0
  4. package/package.json +58 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Skim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # skim-mcp
2
+
3
+ MCP (Model Context Protocol) server for [Skim](https://skim402.com) — clean web
4
+ reader for AI agents. Pays **$0.002 per call in USDC on Base** over the
5
+ [x402](https://x402.org) protocol. No signup. No API keys. No monthly bills.
6
+
7
+ Give your agent the ability to read any URL and get back clean, agent-ready
8
+ Markdown (no nav, no ads, no boilerplate) plus structured metadata (title,
9
+ byline, published date, language, excerpt).
10
+
11
+ ## What you need
12
+
13
+ 1. **Node.js 18+**
14
+ 2. A **Base wallet private key** with a small amount of **USDC** in it. A dollar
15
+ funds ~500 reads. Use a fresh wallet — not your personal one.
16
+
17
+ > Don't have one? Create a key with `cast wallet new` (Foundry) or any EVM
18
+ > wallet, then send USDC to it on Base mainnet from Coinbase, an exchange, or
19
+ > another wallet.
20
+
21
+ ## Install in Claude Desktop
22
+
23
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
24
+ or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "skim": {
30
+ "command": "npx",
31
+ "args": ["-y", "skim-mcp"],
32
+ "env": {
33
+ "SKIM_WALLET_PRIVATE_KEY": "0xYOUR_BASE_WALLET_PRIVATE_KEY"
34
+ }
35
+ }
36
+ }
37
+ }
38
+ ```
39
+
40
+ Restart Claude Desktop. You'll see a new `read_url` tool. Ask Claude to read
41
+ any article and it'll fetch it through Skim and pay automatically.
42
+
43
+ ## Install in Cursor
44
+
45
+ Edit `~/.cursor/mcp.json` (or the in-app **Settings → MCP** panel):
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "skim": {
51
+ "command": "npx",
52
+ "args": ["-y", "skim-mcp"],
53
+ "env": {
54
+ "SKIM_WALLET_PRIVATE_KEY": "0xYOUR_BASE_WALLET_PRIVATE_KEY"
55
+ }
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ ## Install in Cline / Continue / Zed
62
+
63
+ All MCP-compatible clients use the same shape. Run the binary as:
64
+
65
+ ```bash
66
+ npx skim-mcp
67
+ ```
68
+
69
+ with the same `SKIM_WALLET_PRIVATE_KEY` env var.
70
+
71
+ ## Tools
72
+
73
+ ### `read_url`
74
+
75
+ Reads any URL and returns clean Markdown plus a YAML frontmatter block with
76
+ metadata.
77
+
78
+ **Input:**
79
+
80
+ ```json
81
+ { "url": "https://example.com/article" }
82
+ ```
83
+
84
+ **Output (text):**
85
+
86
+ ```
87
+ ---
88
+ title: Example article
89
+ byline: Jane Doe
90
+ published: 2025-01-15
91
+ lang: en
92
+ excerpt: A short summary...
93
+ ---
94
+
95
+ # Example article
96
+
97
+ The cleaned article body in Markdown...
98
+ ```
99
+
100
+ ## Environment variables
101
+
102
+ | Variable | Required | Default | Notes |
103
+ | -------------------------- | -------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
104
+ | `SKIM_WALLET_PRIVATE_KEY` | **yes** | — | Hex private key for the Base wallet that pays for reads. With or without `0x` prefix. |
105
+ | `SKIM_MAX_PRICE_USD` | no | `0.01` | Maximum USD per call. Caps how much the wallet will sign for in a single read. Skim is currently $0.002/call, well under this. |
106
+ | `SKIM_API_URL` | no | `https://skim402.com` | Override the API base URL. Mostly for development. |
107
+
108
+ ## Security
109
+
110
+ - Use a **dedicated wallet**, not your personal one. Fund it with only as much
111
+ USDC as you're willing to spend.
112
+ - The private key never leaves your machine. It's only used locally to sign
113
+ EIP-3009 payment authorizations consumed by the Skim API.
114
+ - Sweep the receive side periodically if you're running Skim yourself.
115
+
116
+ ## How it works
117
+
118
+ 1. The MCP server receives a `read_url` call from your AI agent.
119
+ 2. It POSTs to `https://skim402.com/api/v1/read`.
120
+ 3. The server replies `402 Payment Required` with x402 payment details.
121
+ 4. [`x402-fetch`](https://www.npmjs.com/package/x402-fetch) signs an EIP-3009
122
+ USDC transfer authorization using your wallet, attaches it as the
123
+ `X-PAYMENT` header, and retries.
124
+ 5. Skim verifies + settles via the Coinbase CDP facilitator and returns the
125
+ cleaned content.
126
+
127
+ End-to-end latency is typically <2 seconds.
128
+
129
+ ## Links
130
+
131
+ - Skim — https://skim402.com
132
+ - x402 protocol — https://x402.org
133
+ - Model Context Protocol — https://modelcontextprotocol.io
134
+
135
+ ## License
136
+
137
+ MIT
package/dist/index.js ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { privateKeyToAccount } from "viem/accounts";
5
+ import { wrapFetchWithPayment } from "x402-fetch";
6
+ import { z } from "zod";
7
+ const BASE_URL = (process.env.SKIM_API_URL ?? "https://skim402.com").replace(/\/+$/, "");
8
+ const PRIVATE_KEY = process.env.SKIM_WALLET_PRIVATE_KEY;
9
+ const MAX_PRICE_USD = process.env.SKIM_MAX_PRICE_USD ?? "0.01";
10
+ let payFetch = fetch;
11
+ let walletAddress = null;
12
+ if (PRIVATE_KEY) {
13
+ const normalized = PRIVATE_KEY.startsWith("0x")
14
+ ? PRIVATE_KEY.slice(2)
15
+ : PRIVATE_KEY;
16
+ if (!/^[0-9a-fA-F]{64}$/.test(normalized)) {
17
+ process.stderr.write("skim-mcp: SKIM_WALLET_PRIVATE_KEY must be a 64-character hex string (with or without 0x prefix). Refusing to start.\n");
18
+ process.exit(1);
19
+ }
20
+ const account = privateKeyToAccount(`0x${normalized}`);
21
+ walletAddress = account.address;
22
+ payFetch = wrapFetchWithPayment(fetch, account, BigInt(Math.round(Number(MAX_PRICE_USD) * 1_000_000)));
23
+ }
24
+ const server = new McpServer({
25
+ name: "skim-mcp",
26
+ version: "0.1.0",
27
+ });
28
+ server.tool("read_url", "Fetch any URL and return clean, agent-ready Markdown via Skim (skim402.com). Strips nav, ads, and boilerplate; preserves the article body plus structured metadata (title, byline, published date, language, excerpt). Pays $0.002 per call in USDC on Base over the x402 protocol — no API keys, no signup. Use this whenever you need to read web content: articles, docs, blog posts, GitHub READMEs, research papers, etc.", {
29
+ url: z
30
+ .string()
31
+ .url()
32
+ .describe("The fully-qualified URL to fetch and clean (https://...)."),
33
+ }, async ({ url }) => {
34
+ if (!PRIVATE_KEY) {
35
+ return {
36
+ isError: true,
37
+ content: [
38
+ {
39
+ type: "text",
40
+ text: "Skim requires payment via x402. Set the SKIM_WALLET_PRIVATE_KEY environment variable to a Base wallet funded with USDC. See https://skim402.com for details.",
41
+ },
42
+ ],
43
+ };
44
+ }
45
+ let res;
46
+ try {
47
+ res = await payFetch(`${BASE_URL}/api/v1/read`, {
48
+ method: "POST",
49
+ headers: { "Content-Type": "application/json" },
50
+ body: JSON.stringify({ url, mode: "basic" }),
51
+ });
52
+ }
53
+ catch (err) {
54
+ const msg = err instanceof Error ? err.message : String(err);
55
+ return {
56
+ isError: true,
57
+ content: [
58
+ {
59
+ type: "text",
60
+ text: `Skim request failed: ${msg}. Common causes: wallet has no USDC on Base, or the price exceeds SKIM_MAX_PRICE_USD (${MAX_PRICE_USD}).`,
61
+ },
62
+ ],
63
+ };
64
+ }
65
+ if (!res.ok) {
66
+ const body = await res.text().catch(() => "");
67
+ return {
68
+ isError: true,
69
+ content: [
70
+ {
71
+ type: "text",
72
+ text: `Skim returned ${res.status} ${res.statusText}: ${body || "(no body)"}`,
73
+ },
74
+ ],
75
+ };
76
+ }
77
+ const data = (await res.json());
78
+ const metaLines = data.metadata
79
+ ? Object.entries(data.metadata)
80
+ .filter(([, v]) => v != null && v !== "")
81
+ .map(([k, v]) => `${k}: ${typeof v === "string" ? v : JSON.stringify(v)}`)
82
+ : [];
83
+ const frontmatter = metaLines.length > 0 ? `---\n${metaLines.join("\n")}\n---\n\n` : "";
84
+ return {
85
+ content: [
86
+ {
87
+ type: "text",
88
+ text: frontmatter + (data.markdown ?? data.text ?? ""),
89
+ },
90
+ ],
91
+ };
92
+ });
93
+ const transport = new StdioServerTransport();
94
+ await server.connect(transport);
95
+ // Surface startup status on stderr so MCP clients can show it in their logs
96
+ // without interfering with the stdio JSON-RPC stream.
97
+ if (walletAddress) {
98
+ process.stderr.write(`skim-mcp ready — paying from ${walletAddress} (max $${MAX_PRICE_USD}/call) → ${BASE_URL}\n`);
99
+ }
100
+ else {
101
+ process.stderr.write(`skim-mcp ready (NO WALLET) — set SKIM_WALLET_PRIVATE_KEY to enable paid reads → ${BASE_URL}\n`);
102
+ }
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "skim-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Skim — clean web reader for AI agents. Pays $0.002 per call in USDC over x402. No signup, no API keys.",
5
+ "type": "module",
6
+ "bin": {
7
+ "skim-mcp": "dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.build.json && node -e \"require('fs').chmodSync('dist/index.js', 0o755)\"",
17
+ "typecheck": "tsc --noEmit",
18
+ "dev": "tsx src/index.ts",
19
+ "prepublishOnly": "pnpm build"
20
+ },
21
+ "dependencies": {
22
+ "@modelcontextprotocol/sdk": "^1.0.0",
23
+ "viem": "^2.21.0",
24
+ "x402-fetch": "^0.6.0",
25
+ "zod": "catalog:"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "catalog:",
29
+ "tsx": "catalog:",
30
+ "typescript": "^5.9.0"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public",
34
+ "registry": "https://registry.npmjs.org/"
35
+ },
36
+ "keywords": [
37
+ "mcp",
38
+ "model-context-protocol",
39
+ "x402",
40
+ "skim",
41
+ "ai",
42
+ "agent",
43
+ "reader",
44
+ "markdown",
45
+ "web-scraping",
46
+ "claude",
47
+ "cursor"
48
+ ],
49
+ "homepage": "https://skim402.com",
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "https://github.com/skim402/skim-mcp"
53
+ },
54
+ "license": "MIT",
55
+ "engines": {
56
+ "node": ">=18"
57
+ }
58
+ }