@mrfentmen/rss-mcp 1.0.1 → 1.0.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 (2) hide show
  1. package/dist/api.js +15 -12
  2. package/package.json +1 -1
package/dist/api.js CHANGED
@@ -77,7 +77,7 @@ class Rss2JsonError extends Error {
77
77
  }
78
78
  /** rss2json is a free public endpoint, so the feed is read the same way its siblings are. */
79
79
  async function feed(rssUrl, limit) {
80
- const res = await fetch(`https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(rssUrl)}&count=${limit}&api_key=`, {
80
+ const res = await fetch(`https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(rssUrl)}&count=${limit}`, {
81
81
  headers: { "User-Agent": RSS_UA, Accept: "application/json" },
82
82
  signal: AbortSignal.timeout(30000),
83
83
  });
@@ -97,12 +97,13 @@ export async function searchFeed(args) {
97
97
  if (!query)
98
98
  throw new Rss2JsonError("Provide a word or phrase to look for in the feed's items");
99
99
  const limit = Math.max(1, Math.min(args.limit ?? 20, 100));
100
- const d = await feed(url, Math.min(limit * 3, 100));
101
- const items = d.items ?? [];
100
+ const d = await feed(url, limit);
101
+ const items = (d.items ?? []).slice(0, 10);
102
102
  const hits = items.filter((i) => `${i.title ?? ""} ${i.description ?? ""} ${i.content ?? ""}`.toLowerCase().includes(query));
103
+ const title = d?.feed?.title ?? url;
103
104
  if (!hits.length)
104
- return `None of ${items.length} items in ${d.title ?? url} mention "${query}".`;
105
- return `${hits.length} of ${items.length} items in ${d.title ?? url} mention "${query}":\n` +
105
+ return `None of ${items.length} items in ${title} mention "${query}".`;
106
+ return `${hits.length} of ${items.length} items in ${title} mention "${query}":\n` +
106
107
  hits.slice(0, limit).map((i, n) => `${n + 1}. ${String(i.title ?? "untitled").replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim()}\n ${String(i.pubDate ?? "").slice(0, 25)}\n ${i.link ?? ""}`).join("\n");
107
108
  }
108
109
  /** A feed's own metadata and channel image, which the item list does not show. */
@@ -111,14 +112,16 @@ export async function feedInfo(args) {
111
112
  if (!url)
112
113
  throw new Rss2JsonError("Provide a feed url to describe");
113
114
  const d = await feed(url, 1);
115
+ // rss2json nests the channel metadata under "feed".
116
+ const f = d?.feed ?? {};
114
117
  return [
115
- `Feed: ${d.title ?? "untitled"}`,
116
- d.description ? `about: ${String(d.description).replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim().slice(0, 300)}` : null,
117
- d.link ? `site: ${d.link}` : null,
118
- d.feedUrl ? `feed url: ${d.feedUrl}` : null,
119
- d.image ? `image: ${d.image}` : null,
120
- `items available: ${d.items?.length ?? 0} (rss2json caps a single call at 100)`,
121
- d.copyright ? `copyright: ${d.copyright}` : null,
118
+ `Feed: ${f.title ?? "untitled"}`,
119
+ f.description ? `about: ${String(f.description).replace(/<[^>]*>/g, " ").replace(/\s+/g, " ").trim().slice(0, 300)}` : null,
120
+ f.link ? `site: ${f.link}` : null,
121
+ f.url ? `feed url: ${f.url}` : null,
122
+ f.author ? `author: ${f.author}` : null,
123
+ f.image ? `image: ${f.image}` : null,
124
+ `items returned: ${d?.items?.length ?? 0} (rss2json returns 10 per call without a paid key)`,
122
125
  ]
123
126
  .filter(Boolean)
124
127
  .join("\n");
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.1",
2
+ "version": "1.0.3",
3
3
  "type": "module",
4
4
  "repository": {
5
5
  "type": "git",