From 7b61737ff852a3386a8e28ddbb318d5096114a33 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sat, 7 Nov 2026 02:39:07 +0000 Subject: [PATCH] MCP: trending_topics tool Co-Authored-By: Claude Opus 5.5 --- apps/web/public/.well-known/openmcp.json | 1 + apps/web/src/lib/llms.js | 2 +- apps/web/src/lib/mcp/tools.js | 23 ++++++++++++++++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/web/public/.well-known/openmcp.json b/apps/web/public/.well-known/openmcp.json index c3a7b46..e93a3f1 100644 --- a/apps/web/public/.well-known/openmcp.json +++ b/apps/web/public/.well-known/openmcp.json @@ -26,6 +26,7 @@ "list_authors", "get_author", "directory_stats", + "trending_topics", "submit_feed", "get_openprofile", "update_openprofile", diff --git a/apps/web/src/lib/llms.js b/apps/web/src/lib/llms.js index 9a7067c..4e33174 100644 --- a/apps/web/src/lib/llms.js +++ b/apps/web/src/lib/llms.js @@ -143,7 +143,7 @@ export async function llmsTxt(opts = {}) { '', 'The same capabilities as the endpoints below, as tools an agent can call:', 'search, list_feeds, get_feed, list_topics, get_topic, topic_posts, read_post,', - 'random_feed, directory_stats and submit_feed. Point an MCP client at', + 'random_feed, directory_stats, trending_topics and submit_feed. Point an MCP client at', `\`${base}/mcp\` — it answers both the current protocol revision and the`, 'older handshake-based ones. Documentation for humans is at the same URL in a', `browser: ${base}/mcp`, diff --git a/apps/web/src/lib/mcp/tools.js b/apps/web/src/lib/mcp/tools.js index f8e25aa..ca352bb 100644 --- a/apps/web/src/lib/mcp/tools.js +++ b/apps/web/src/lib/mcp/tools.js @@ -1,4 +1,4 @@ -import { q, newId, authors as people, webrings } from '@rssamplifier/db'; +import { q, newId, authors as people, trends, webrings } from '@rssamplifier/db'; import { topicSlug } from '@rssamplifier/feed'; import { submitCatalogue, hashIp, EXPRESS_MAX } from '@rssamplifier/ingest'; import { submitFeedTool } from '@profullstack/submit-feed/core'; @@ -652,6 +652,27 @@ export const TOOLS = [ }, }, + { + name: 'trending_topics', + title: 'What the open web is writing about more than last week', + description: + 'Subjects English blogs and news sites used in headlines more than the week before, ranked. `count` is feeds, not posts, in a one in four sample, so it measures movement rather than coverage, and `prior_count` is the same figure for the week before. Updated daily. An empty list means the rollup has not got two days to compare yet.', + inputSchema: { + type: 'object', + properties: { + window: { type: 'integer', minimum: 1, maximum: 14, description: 'Days per side of the comparison. Default 7.' }, + limit: { type: 'integer', minimum: 1, maximum: 200, description: 'Default 50.' }, + }, + }, + annotations: { readOnlyHint: true, openWorldHint: true }, + async run({ window = 7, limit = 50 } = {}) { + const size = Math.min(14, Math.max(1, Math.round(Number(window)) || 7)); + const top = Math.min(200, Math.max(1, Math.round(Number(limit)) || 50)); + const result = await trends.trendingTerms(db(), { window: size, limit: top }); + return { window_days: size, generated_at: result.generatedAt, documents: result.feeds, topics: result.topics }; + }, + }, + { name: 'list_rings', title: 'List the webrings this site hosts',