skim-mcp 0.2.2 → 0.2.3

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 (3) hide show
  1. package/README.md +17 -1
  2. package/dist/index.js +44 -1
  3. package/package.json +9 -10
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![MCP Registry](https://img.shields.io/badge/MCP-Registry-blue)](https://registry.modelcontextprotocol.io/v0/servers?search=skim402)
7
7
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
8
8
 
9
- `skim-mcp` is the official Model Context Protocol server for [Skim](https://skim402.com) — the clean reader API for AI agents. It exposes `read_url`, `read_urls` (batch), `extract_url` (structured / table), `crawl_url`, `read_pdf`, `watch_urls`, and `check_watch`. The default path is a card-plan API key (`SKIM_API_KEY`); x402 wallet pay stays optional.
9
+ `skim-mcp` is the official Model Context Protocol server for [Skim](https://skim402.com) — the clean reader API for AI agents. It exposes `read_url`, `read_urls` (batch), `extract_url` (structured / table), `crawl_url`, `read_pdf`, `watch_urls`, `check_watch`, and `poll_signal`. The default path is a card-plan API key (`SKIM_API_KEY`); x402 wallet pay stays optional.
10
10
 
11
11
  > **See it before you wire it:** [try Skim free in your browser](https://freeskims.skim402.com) — 10 free skims a day, no signup. Paste a URL, see exactly what your agent gets back.
12
12
 
@@ -177,6 +177,20 @@ Register 1–20 URLs, then poll for content diffs. `watch_id` is a secret.
177
177
 
178
178
  Card-lane `/api/t/watch*` is live (POST without a key returns `401`). Optional HTTPS `webhookUrl` is supported by the API; this MCP tool still sends `{ urls, note? }`.
179
179
 
180
+ ### `poll_signal`
181
+
182
+ Poll a [Skim Signal](https://skim402.com/signals) and return the latest structured items (title, summary, source, timestamp, link, and entities). **2 credits** per successful poll; failed polls are refunded.
183
+
184
+ **Requires `SKIM_API_KEY`.** The card-lane routes are `GET /api/t/signal/{slug}/latest?limit=` and `GET /api/t/feeds/x402/latest?limit=` for the x402 ecosystem feed.
185
+
186
+ **Input:** `{ "slug": "ai-news", "limit": 20 }`
187
+
188
+ Optional documented filters: `forms` (SEC filings and campaign finance), `categories` (deals), `fields` (research), `states` (film incentives), and `committees` (campaign finance).
189
+
190
+ ```
191
+ Poll the ai-news Signal for the latest 20 items.
192
+ ```
193
+
180
194
  ### Example agent prompts
181
195
 
182
196
  ```
@@ -190,6 +204,8 @@ Crawl https://example.com (max 10 pages) and list the page titles.
190
204
 
191
205
  Read the PDF at https://example.com/paper.pdf and summarize it.
192
206
 
207
+ Poll the ai-news Signal for the latest 20 items.
208
+
193
209
  Watch https://competitor.com/pricing and https://competitor.com/changelog, then check the watch for changes.
194
210
  ```
195
211
 
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
4
4
  import { privateKeyToAccount } from "viem/accounts";
5
5
  import { wrapFetchWithPayment } from "x402-fetch";
6
6
  import { z } from "zod";
7
- const VERSION = "0.2.1";
7
+ const VERSION = "0.2.3";
8
8
  const BASE_URL = (process.env.SKIM_API_URL ?? "https://skim402.com").replace(/\/+$/, "");
9
9
  const API_KEY = process.env.SKIM_API_KEY ?? "";
10
10
  const PRIVATE_KEY = process.env.SKIM_WALLET_PRIVATE_KEY ?? "";
@@ -154,6 +154,14 @@ function authMissing() {
154
154
  function cardLaneOnly(tool, path) {
155
155
  return fail(`${tool} is card-lane only (${path}) — there is no x402 /v1 twin. Set SKIM_API_KEY (sk402_..., free tier at skim402.com/pricing). Wallet pay still works for read_url, read_urls, extract_url, and watch.`);
156
156
  }
157
+ const SIGNAL_SLUGS = [
158
+ "ai-news", "sec-filings", "crypto-news", "macro", "security", "regulations",
159
+ "courts", "recalls", "deals", "launches", "trending", "research", "energy",
160
+ "entertainment", "studio-jobs", "campaign-finance", "film-incentives", "x402",
161
+ ];
162
+ function signalPollPath(slug) {
163
+ return slug === "x402" ? "/api/t/feeds/x402/latest" : `/api/t/signal/${slug}/latest`;
164
+ }
157
165
  function buildUrl(path, query) {
158
166
  const url = new URL(path, `${BASE_URL}/`);
159
167
  if (query) {
@@ -485,6 +493,41 @@ server.tool("check_watch", "Poll a Skim Watch for content changes (or fetch regi
485
493
  return fail(requestFailedMessage(err));
486
494
  }
487
495
  });
496
+ server.tool("poll_signal", "Poll a Skim Signal feed and return the latest structured items. 2 credits per successful poll; failed polls are refunded. Requires SKIM_API_KEY because the wallet lane uses a v2 402 handshake that x402-fetch does not support for these GET feeds.", {
497
+ slug: z.enum(SIGNAL_SLUGS).describe("Signal slug. Use x402 for the ecosystem feed."),
498
+ limit: z.number().int().min(1).max(100).optional().describe("Max items, newest first. Default 50, capped at 100."),
499
+ forms: z.string().optional().describe("Comma-separated form filter for sec-filings or campaign-finance."),
500
+ categories: z.string().optional().describe("Comma-separated category filter for deals."),
501
+ fields: z.string().optional().describe("Comma-separated arXiv field filter for research."),
502
+ states: z.string().optional().describe("Comma-separated two-letter state filter for film-incentives."),
503
+ committees: z.string().optional().describe("Comma-separated committee-name filter for campaign-finance."),
504
+ }, async ({ slug, limit, forms, categories, fields, states, committees }) => {
505
+ if (!hasAuth)
506
+ return authMissing();
507
+ if (!cardLane) {
508
+ return fail("poll_signal is card-lane only. Set SKIM_API_KEY (sk402_..., free tier at skim402.com/pricing).");
509
+ }
510
+ try {
511
+ const query = {};
512
+ if (limit !== undefined)
513
+ query.limit = String(limit);
514
+ if (forms)
515
+ query.forms = forms;
516
+ if (categories)
517
+ query.categories = categories;
518
+ if (fields)
519
+ query.fields = fields;
520
+ if (states)
521
+ query.states = states;
522
+ if (committees)
523
+ query.committees = committees;
524
+ const res = await skimFetch("GET", signalPollPath(slug), { query });
525
+ return ok(JSON.stringify(await readJson(res), null, 2));
526
+ }
527
+ catch (err) {
528
+ return fail(requestFailedMessage(err));
529
+ }
530
+ });
488
531
  const transport = new StdioServerTransport();
489
532
  await server.connect(transport);
490
533
  if (cardLane) {
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "skim-mcp",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "mcpName": "io.github.JessieJanie/skim402",
5
- "description": "MCP server for Skim — clean web reader for AI agents. Card API key or x402 wallet. Batch, extract, crawl, PDF, watch.",
5
+ "description": "MCP server for Skim — clean web reader for AI agents. Card API key or x402 wallet. Batch, extract, crawl, PDF, watch, signals.",
6
6
  "type": "module",
7
7
  "bin": {
8
8
  "skim-mcp": "dist/index.js"
@@ -13,13 +13,6 @@
13
13
  "README.md",
14
14
  "LICENSE"
15
15
  ],
16
- "scripts": {
17
- "build": "tsc -p tsconfig.build.json && node -e \"require('fs').chmodSync('dist/index.js', 0o755)\"",
18
- "typecheck": "tsc --noEmit",
19
- "dev": "tsx src/index.ts",
20
- "prepublishOnly": "pnpm build",
21
- "postinstall": "npm install -g tsx@4.21.0"
22
- },
23
16
  "dependencies": {
24
17
  "@modelcontextprotocol/sdk": "^1.0.0",
25
18
  "viem": "^2.21.0",
@@ -56,5 +49,11 @@
56
49
  "license": "MIT",
57
50
  "engines": {
58
51
  "node": ">=18"
52
+ },
53
+ "scripts": {
54
+ "build": "tsc -p tsconfig.build.json && node -e \"require('fs').chmodSync('dist/index.js', 0o755)\"",
55
+ "typecheck": "tsc --noEmit",
56
+ "dev": "tsx src/index.ts",
57
+ "postinstall": "npm install -g tsx@4.21.0"
59
58
  }
60
- }
59
+ }