@tensorfeed/mcp-server 1.26.0 → 1.28.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/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to the [TensorFeed.ai MCP server](https://github.com/RipperMercs/tensorfeed-mcp). Free tools work without configuration; premium tools require a bearer token via the `TENSORFEED_TOKEN` env var. Buy credits at [tensorfeed.ai/developers/agent-payments](https://tensorfeed.ai/developers/agent-payments).
4
4
 
5
+ ## 1.28.0 - 2026-05-13
6
+
7
+ ### Added
8
+ - `get_ai_supply_chain_iocs` (free): wraps `/api/security/ai-supply-chain-iocs.json`. Daily-refreshed list of GitHub Security Advisory entries filtered by AI/ML/LLM/MCP keyword vocabulary across npm, PyPI, Go, Maven, and other package ecosystems. Each row carries the package name, ecosystem, GHSA advisory ID, severity, summary, vulnerable version range, publication date, and the canonical GHSA URL. Optional `severity` and `ecosystem` filters; `limit` caps result count (default 25, max 100). Republish posture: TensorFeed re-publishes already-public advisories; the linked GHSA record is authoritative. Useful for MCP-server reviewers, AI-tool maintainers, and supply-chain monitors that want a single AI-relevant feed rather than parsing all of GHSA.
9
+
10
+ Tool count: 45 -> 46. Lands the same security feed that caught the @mistralai npm worm on day 1, now reachable as an MCP tool for defenders running agentic supply-chain audits.
11
+
12
+ ## 1.27.0 - 2026-05-09
13
+
14
+ ### Added
15
+ - `get_recent_earthquakes` (free): wraps `/api/climate/earthquakes`. USGS Earthquake Hazards Program pre-built summary feeds. Magnitude bucket (significant | 4.5 | 2.5 | 1.0 | all) crossed with period (hour | day | week | month). Returns id, magnitude, place, time, depth, lat/lon, tsunami flag, USGS detail URL. License: US Government public domain (17 USC §105).
16
+ - `get_weather_alerts` (free, US-only): wraps `/api/climate/weather-alerts`. NWS Active Weather Alerts. Filter by 2-letter state, exact NWS event name, severity, urgency, status. Returns flattened alerts list with effective/expires windows and the canonical NWS web URL. License: US Government public domain.
17
+ - `get_agent_opportunities` (free): wraps `/api/agents/opportunities`. Daily 13:30 UTC scan of new repositories across the AI agent ecosystem (Anthropic / OpenAI / Microsoft / ModelContextProtocol / HuggingFace / LangChain / frontier-lab orgs plus MCP, x402, agent-skills keyword sweeps and a vertical-pattern catch). Eleven signals deduped + composite-scored with per-signal MIN/MAX caps so smaller signals are never starved. Optional `signal` filter to one source.
18
+
19
+ Tool count: 42 -> 45. Brings the stdio package up to parity with the new public-domain feeds and the daily agent-ecosystem scan that landed on the hosted HTTP transport this same day.
20
+
5
21
  ## 1.26.0 - 2026-05-09
6
22
 
7
23
  ### Added
package/dist/index.js CHANGED
@@ -267,6 +267,62 @@ registerTool('get_agent_activity', 'Get live AI bot traffic on TensorFeed.ai. Re
267
267
  ],
268
268
  };
269
269
  });
270
+ // ── Tool: get_ai_supply_chain_iocs ──────────────────────────────────
271
+ registerTool('get_ai_supply_chain_iocs', 'Get the latest AI/ML supply-chain indicators-of-compromise from the TensorFeed defender feed. Daily-refreshed list of GitHub Security Advisory entries filtered by AI/ML/LLM/MCP keyword vocabulary across npm, PyPI, Go, Maven, and other ecosystems. Each entry includes the package name, ecosystem, GHSA advisory ID, severity, summary, vulnerable version range, publication date, and a link to the authoritative GHSA record. Pure data feed: TensorFeed re-publishes already-public advisories, does not detect malware, and does not attribute it. Always treat the linked GHSA record as authoritative. Useful for AI-tool maintainers, MCP-server reviewers, and supply-chain monitors that want a single feed of AI-relevant advisories rather than parsing all of GHSA.', {
272
+ severity: z
273
+ .enum(['critical', 'high', 'moderate', 'low'])
274
+ .optional()
275
+ .describe('Filter to a single GHSA severity tier'),
276
+ ecosystem: z
277
+ .string()
278
+ .optional()
279
+ .describe('Filter to a single package ecosystem (e.g. "npm", "pypi", "go", "maven")'),
280
+ limit: z
281
+ .number()
282
+ .min(1)
283
+ .max(100)
284
+ .optional()
285
+ .describe('Maximum number of advisories to return (default 25, max 100)'),
286
+ }, async ({ severity, ecosystem, limit }) => {
287
+ const data = (await fetchJSON('/security/ai-supply-chain-iocs.json'));
288
+ const sevWanted = severity?.toLowerCase();
289
+ const ecoWanted = ecosystem?.toLowerCase();
290
+ const filtered = data.entries.filter((e) => {
291
+ if (sevWanted && e.severity.toLowerCase() !== sevWanted)
292
+ return false;
293
+ if (ecoWanted && e.package.ecosystem.toLowerCase() !== ecoWanted)
294
+ return false;
295
+ return true;
296
+ });
297
+ const cap = Math.min(limit ?? 25, 100);
298
+ const rows = filtered.slice(0, cap);
299
+ if (rows.length === 0) {
300
+ return {
301
+ content: [
302
+ {
303
+ type: 'text',
304
+ text: `No AI supply-chain IOCs matched (total in feed: ${data.total}, generated ${data.generated_at}).`,
305
+ },
306
+ ],
307
+ };
308
+ }
309
+ const body = rows
310
+ .map((e, i) => {
311
+ const kw = e.ai_relevance?.matched_keywords?.length
312
+ ? ` [matched: ${e.ai_relevance.matched_keywords.join(', ')}]`
313
+ : '';
314
+ return [
315
+ `${i + 1}. ${e.package.ecosystem}: ${e.package.name} (${e.severity.toUpperCase()})`,
316
+ ` ${e.summary}`,
317
+ ` GHSA: ${e.advisory_id} ${e.url}`,
318
+ ` Affected: ${e.vulnerable_version_range} Published: ${e.published_at}${kw}`,
319
+ ].join('\n');
320
+ })
321
+ .join('\n\n');
322
+ const header = `AI supply-chain IOCs (${rows.length} of ${filtered.length} matched, ${data.total} in feed, generated ${data.generated_at}):`;
323
+ const footer = `\n\nPosture: ${data.posture}`;
324
+ return { content: [{ type: 'text', text: `${header}\n\n${body}${footer}` }] };
325
+ });
270
326
  // ════════════════════════════════════════════════════════════════════
271
327
  // PREMIUM TOOLS (require TENSORFEED_TOKEN env var, paid in USDC on Base)
272
328
  // ════════════════════════════════════════════════════════════════════
@@ -1180,6 +1236,105 @@ registerTool('get_hf_daily_papers', 'Hugging Face Daily Papers: editor-curated A
1180
1236
  return { content: [{ type: 'text', text }] };
1181
1237
  });
1182
1238
  // ── Tool: get_ai_ecosystem_today (free, composite) ──────────────────
1239
+ // ── Tool: get_recent_earthquakes (free) ─────────────────────────────
1240
+ registerTool('get_recent_earthquakes', "Recent earthquakes from the USGS Earthquake Hazards Program pre-built summary feeds. Choose a magnitude bucket (significant | 4.5 | 2.5 | 1.0 | all) and a time window (hour | day | week | month). Returns id, magnitude, place, time (ISO 8601), depth_km, longitude, latitude, tsunami flag, USGS detail URL. Upstream feeds refresh every minute. License: US Government public domain (17 USC §105). Free, no auth.", {
1241
+ magnitude: z.enum(['significant', '4.5', '2.5', '1.0', 'all']).optional().describe('Magnitude bucket (default 4.5)'),
1242
+ period: z.enum(['hour', 'day', 'week', 'month']).optional().describe('Time window (default day)'),
1243
+ limit: z.number().min(1).max(50).optional().describe('Max earthquakes to render (default 15, max 50). Worker accepts up to 500 but text rendering caps lower.'),
1244
+ }, async ({ magnitude, period, limit }) => {
1245
+ const params = new URLSearchParams();
1246
+ params.set('magnitude', magnitude ?? '4.5');
1247
+ params.set('period', period ?? 'day');
1248
+ params.set('limit', String(Math.min(limit ?? 15, 50)));
1249
+ const data = (await fetchJSON(`/climate/earthquakes?${params}`));
1250
+ if (!data.ok || !data.earthquakes) {
1251
+ return { content: [{ type: 'text', text: `USGS earthquakes unavailable: ${data.error ?? 'unknown error'}` }] };
1252
+ }
1253
+ const eqs = data.earthquakes;
1254
+ const lines = eqs.map((q, i) => {
1255
+ const mag = q.magnitude !== null ? `M${q.magnitude.toFixed(1)}` : 'M?';
1256
+ const tsu = q.tsunami ? ' [tsunami flag]' : '';
1257
+ const time = q.time ? q.time.slice(0, 19).replace('T', ' ') + ' UTC' : 'unknown time';
1258
+ const depth = q.depth_km !== null ? `${q.depth_km.toFixed(0)}km deep` : 'depth unknown';
1259
+ const coords = q.latitude !== null && q.longitude !== null ? ` (${q.latitude.toFixed(2)}, ${q.longitude.toFixed(2)})` : '';
1260
+ return `${i + 1}. ${mag} ${q.place ?? 'location unknown'}${coords}\n ${time}, ${depth}${tsu}\n ${q.url ?? ''}`;
1261
+ }).join('\n\n');
1262
+ const meta = data.feed_metadata;
1263
+ const header = `USGS earthquakes (${data.query?.magnitude ?? '?'} / ${data.query?.period ?? '?'}). ${eqs.length} of ${meta?.upstream_count ?? '?'} returned.`;
1264
+ return { content: [{ type: 'text', text: `${header}\n\n${lines || ' (no events in this window)'}\n\nSource: USGS Earthquake Hazards Program. Public domain (17 USC §105).` }] };
1265
+ });
1266
+ // ── Tool: get_weather_alerts (free, US only) ────────────────────────
1267
+ registerTool('get_weather_alerts', "Active US weather alerts from the National Weather Service. US-only. Filter by 2-letter state code (area), exact NWS event name, severity, urgency, status. Returns id, event, severity, urgency, headline, description, areaDesc, sent/effective/expires/ends, sender_name, web URL. Active alerts only — expired alerts fall off the upstream feed automatically. License: US Government public domain. Free, no auth.", {
1268
+ area: z.string().regex(/^[A-Za-z]{2}$/).optional().describe('2-letter US state or territory code (CA, TX, PR, etc)'),
1269
+ event: z.string().optional().describe('Exact NWS event name (e.g. "Tornado Warning", "Heat Advisory")'),
1270
+ severity: z.enum(['Extreme', 'Severe', 'Moderate', 'Minor', 'Unknown']).optional().describe('Severity filter'),
1271
+ urgency: z.enum(['Immediate', 'Expected', 'Future', 'Past', 'Unknown']).optional().describe('Urgency filter'),
1272
+ status: z.enum(['actual', 'exercise', 'system', 'test', 'draft']).optional().describe('Status filter (default actual unfiltered)'),
1273
+ limit: z.number().min(1).max(50).optional().describe('Max alerts to render (default 15, max 50). Worker accepts up to 500 but text rendering caps lower.'),
1274
+ }, async ({ area, event, severity, urgency, status, limit }) => {
1275
+ const params = new URLSearchParams();
1276
+ if (area)
1277
+ params.set('area', area.toUpperCase());
1278
+ if (event)
1279
+ params.set('event', event);
1280
+ if (severity)
1281
+ params.set('severity', severity);
1282
+ if (urgency)
1283
+ params.set('urgency', urgency);
1284
+ if (status)
1285
+ params.set('status', status);
1286
+ params.set('limit', String(Math.min(limit ?? 15, 50)));
1287
+ const data = (await fetchJSON(`/climate/weather-alerts?${params}`));
1288
+ if (!data.ok || !data.alerts) {
1289
+ return { content: [{ type: 'text', text: `NWS weather alerts unavailable: ${data.error ?? 'unknown error'}` }] };
1290
+ }
1291
+ const alerts = data.alerts;
1292
+ const lines = alerts.map((a, i) => {
1293
+ const ev = a.event ?? 'unknown event';
1294
+ const sev = a.severity ? `[${a.severity}]` : '';
1295
+ const eff = a.effective ? a.effective.slice(0, 19).replace('T', ' ') + ' UTC' : '';
1296
+ const exp = a.expires ? a.expires.slice(0, 19).replace('T', ' ') + ' UTC' : 'no expiry';
1297
+ return `${i + 1}. ${sev} ${ev}\n Where: ${a.area_desc ?? 'unspecified'}\n ${a.headline ?? ''}\n Effective: ${eff} → ${exp}\n ${a.web ?? ''}`;
1298
+ }).join('\n\n');
1299
+ const filters = [];
1300
+ if (area)
1301
+ filters.push(`area=${area.toUpperCase()}`);
1302
+ if (event)
1303
+ filters.push(`event=${event}`);
1304
+ if (severity)
1305
+ filters.push(`severity=${severity}`);
1306
+ const filterText = filters.length > 0 ? ` (${filters.join(', ')})` : '';
1307
+ const header = `NWS active US weather alerts${filterText}. ${alerts.length} of ${data.feed_metadata?.upstream_count ?? '?'} returned.`;
1308
+ return { content: [{ type: 'text', text: `${header}\n\n${lines || ' (no active alerts matching filters)'}\n\nSource: api.weather.gov. Public domain (17 USC §105). US-only coverage.` }] };
1309
+ });
1310
+ // ── Tool: get_agent_opportunities (free) ────────────────────────────
1311
+ registerTool('get_agent_opportunities', "TensorFeed's daily scan of new repositories across the AI agent ecosystem (Anthropic, OpenAI, Microsoft, ModelContextProtocol, HuggingFace, LangChain, frontier-lab orgs) plus recent MCP, x402, and skill keyword sweeps. Eleven signals total, deduped + composite-scored (signal_weight × log10(stars+1) × recency decay) with per-signal MIN/MAX caps so smaller signals are never starved. Refreshed daily at 13:30 UTC. Useful for surfacing distribution targets, integration ideas, or a daily brief on what's launching across the agent space. Free, no auth.", {
1312
+ signal: z.enum([
1313
+ 'anthropic-org', 'openai-org', 'microsoft-org', 'mcp-org', 'huggingface-org',
1314
+ 'langchain-org', 'frontier-labs', 'mcp-keyword', 'x402-keyword', 'skill-keyword',
1315
+ 'vertical-pattern',
1316
+ ]).optional().describe('Filter to one signal source. Omit to get the cross-signal ranked top-N.'),
1317
+ limit: z.number().min(1).max(25).optional().describe('Max opportunities to render (default 10, max 25)'),
1318
+ }, async ({ signal, limit }) => {
1319
+ const data = (await fetchJSON('/agents/opportunities'));
1320
+ if (data.error) {
1321
+ return { content: [{ type: 'text', text: `Agent opportunities unavailable: ${data.error}` }] };
1322
+ }
1323
+ const all = data.opportunities ?? [];
1324
+ const filtered = signal ? all.filter(o => o.signal === signal) : all;
1325
+ const cap = Math.min(limit ?? 10, 25);
1326
+ const top = filtered.slice(0, cap);
1327
+ const lines = top.map((o, i) => {
1328
+ const updated = o.updated_at ? o.updated_at.slice(0, 10) : '';
1329
+ const desc = o.description ? `\n ${o.description.length > 140 ? o.description.slice(0, 140) + '...' : o.description}` : '';
1330
+ return `${i + 1}. [${o.signal}] ${o.full_name} ${o.stars.toLocaleString()}★, score ${o.composite_score.toFixed(1)}, updated ${updated}${desc}\n ${o.html_url}`;
1331
+ }).join('\n\n');
1332
+ const filt = signal ? ` filtered to ${signal}` : '';
1333
+ const header = `Agent ecosystem opportunities for ${data.date ?? 'today'}${filt}. ${top.length} of ${filtered.length} (total snapshot: ${data.total_opportunities ?? all.length}).`;
1334
+ const bySignal = data.summary?.by_signal ? Object.entries(data.summary.by_signal).map(([k, v]) => `${k}=${v}`).join(', ') : '';
1335
+ const sig = bySignal ? `\nBy signal: ${bySignal}` : '';
1336
+ return { content: [{ type: 'text', text: `${header}${sig}\n\n${lines || ' (no opportunities returned)'}\n\nSource: TensorFeed daily GitHub scan via the public Search API.` }] };
1337
+ });
1183
1338
  // Single fetch to /api/today which fans out worker-side. The previous
1184
1339
  // implementation made 9 separate fetches per agent invocation; now
1185
1340
  // the worker's edge cache absorbs the load and serves one cached
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tensorfeed/mcp-server",
3
- "version": "1.26.0",
3
+ "version": "1.28.0",
4
4
  "mcpName": "ai.tensorfeed/mcp-server",
5
5
  "description": "MCP server for TensorFeed.ai - AI news, status, model data, and premium endpoints (routing, cost projection, forecast, history series, news search, webhook watches with digest tier, enriched directory) for AI agents",
6
6
  "main": "dist/index.js",
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "ai.tensorfeed/mcp-server",
4
4
  "title": "TensorFeed",
5
5
  "description": "AI news, model pricing, service status, and machine-payable premium tools. AFTA-certified.",
6
- "version": "1.26.0",
6
+ "version": "1.27.0",
7
7
  "websiteUrl": "https://tensorfeed.ai/developers/agent-payments",
8
8
  "repository": {
9
9
  "url": "https://github.com/RipperMercs/tensorfeed-mcp",
@@ -20,7 +20,7 @@
20
20
  "registryType": "npm",
21
21
  "registryBaseUrl": "https://registry.npmjs.org",
22
22
  "identifier": "@tensorfeed/mcp-server",
23
- "version": "1.26.0",
23
+ "version": "1.27.0",
24
24
  "runtimeHint": "npx",
25
25
  "transport": {
26
26
  "type": "stdio"
@@ -59,6 +59,9 @@
59
59
  "get_openrouter_models",
60
60
  "get_hf_daily_papers",
61
61
  "get_ai_ecosystem_today",
62
+ "get_recent_earthquakes",
63
+ "get_weather_alerts",
64
+ "get_agent_opportunities",
62
65
  "pricing_series_free",
63
66
  "benchmark_series_free",
64
67
  "status_uptime_free",