@tensorfeed/mcp-server 1.28.0 → 1.30.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 +24 -0
- package/dist/index.js +172 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,30 @@
|
|
|
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.30.0 - 2026-05-14
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
- Every paid tool description now advertises the USD price alongside the credit cost. "Costs 1 credit." -> "Costs 1 credit ($0.02).". Lets agents budget calls without needing to look up credit-to-USD conversion separately. No behavior change; pure description metadata.
|
|
9
|
+
|
|
10
|
+
### Changed (strict-premium tier)
|
|
11
|
+
- Six tools now flagged as "Strict premium, no free trial" in their descriptions: `pricing_series`, `benchmark_series`, `status_uptime`, `status_leaderboard`, `provider_deepdive`, `probe_series_premium`. These map to TF Worker paths in the strict-premium set (worker/src/strict-premium-endpoints.ts) which bypasses the per-IP 100-call/day free trial. Their free 7-day-capped siblings (`pricing_series_free`, `benchmark_series_free`, `status_uptime_free`, `status_leaderboard_free`) remain the discovery option. Agents that hit these without auth get a 402 immediately with a strict-premium-specific message, not the free-trial advert.
|
|
12
|
+
- Rationale: per the TF 70/30 premium-lock framework, full-window historical time-series and heavy aggregations are TF's moat and warrant strict gating during the demand-discovery phase. Pricing per call is unchanged at this version; repricing into a higher tier is a separate future decision.
|
|
13
|
+
|
|
14
|
+
## 1.29.0 - 2026-05-13
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- `get_honeypot_iocs` (free): wraps `/api/security/iocs.json`. First-party honeypot indicators-of-compromise observed against TensorFeed.ai trap endpoints over the last 30 days. Filter by `type` (ip / ua / path), cap with `limit` (default 50, max 500). License CC0; pure first-party observation, not a re-export. Pairs with `get_ai_supply_chain_iocs` (GHSA-derived) for a two-layer defender feed.
|
|
18
|
+
- `check_afta_certification` (free): wraps `/api/afta-certify/check`. Runs 6 deterministic AFTA probes (well-known endpoints, x402 manifest, pricing transparency, free trial, federation membership, signed receipts) against any domain and returns score, verdict, and per-check pass/fail. Useful for federation prospects, agent governance audits, and demand-side trust signals.
|
|
19
|
+
- `get_agent_reputation_card` (free): wraps `/api/agents/reputation/{wallet}` and `/api/agents/reputation/by-token/{prefix}`. Returns the Agent Reputation Bureau card for an EVM wallet or tf_live_ token prefix: reliability, activity, spend, streak, composite trust score, trust grade (S/A/B/C/D), flags, claim status, leaderboard ranks. Cards rebuild daily 04:50 UTC. Returns a helpful 404 hint when no card exists yet.
|
|
20
|
+
|
|
21
|
+
### Added (MCP primitive)
|
|
22
|
+
- `tensorfeed://news/latest` resource: latest 20 AI news articles as a JSON resource. First TF use of the MCP `resources` primitive, exposed alongside the existing `get_ai_news` tool. Hosts that prefer data-shaped surfaces (Claude Desktop, some agent frameworks) can attach the news feed directly without going through tool-call decision loops.
|
|
23
|
+
|
|
24
|
+
### Fixed
|
|
25
|
+
- `registerTool` now auto-infers `PREMIUM_READ_TOOL` annotations (`idempotentHint: false`) for any tool whose description includes "Costs N credit". Previously all read tools defaulted to `idempotentHint: true`, which meant agents that retried paid calls on transient failure could double-charge users. Affects every paid read tool (premium_routing, pricing_series, benchmark_series, status_uptime, status_leaderboard, premium_agents_directory, whats_new, compare_models, provider_deepdive, cost_projection, news_search, probe_series_premium). Write tools (create_*_watch / delete_watch) keep their explicit CREATE_TOOL / DELETE_TOOL annotations and bypass the inference.
|
|
26
|
+
|
|
27
|
+
Tool count: 46 -> 49. First MCP resource live. Annotations now spec-honest about retry semantics.
|
|
28
|
+
|
|
5
29
|
## 1.28.0 - 2026-05-13
|
|
6
30
|
|
|
7
31
|
### Added
|
package/dist/index.js
CHANGED
|
@@ -78,6 +78,16 @@ const READ_TOOL = {
|
|
|
78
78
|
idempotentHint: true,
|
|
79
79
|
openWorldHint: true,
|
|
80
80
|
};
|
|
81
|
+
// Paid read tools: same as READ_TOOL but idempotentHint: false because each
|
|
82
|
+
// call burns a credit. Agents that retry on transient failure under
|
|
83
|
+
// READ_TOOL semantics would double-charge users on flaky networks. Applied
|
|
84
|
+
// automatically below when a tool's description includes "Costs N credit".
|
|
85
|
+
const PREMIUM_READ_TOOL = {
|
|
86
|
+
readOnlyHint: true,
|
|
87
|
+
destructiveHint: false,
|
|
88
|
+
idempotentHint: false,
|
|
89
|
+
openWorldHint: true,
|
|
90
|
+
};
|
|
81
91
|
const CREATE_TOOL = {
|
|
82
92
|
readOnlyHint: false,
|
|
83
93
|
destructiveHint: false,
|
|
@@ -90,15 +100,50 @@ const DELETE_TOOL = {
|
|
|
90
100
|
idempotentHint: true,
|
|
91
101
|
openWorldHint: true,
|
|
92
102
|
};
|
|
93
|
-
|
|
103
|
+
const PAID_TOOL_RE = /Costs \d+ credit/i;
|
|
104
|
+
function registerTool(name, description, paramsSchema, cb, annotations) {
|
|
105
|
+
// When no explicit annotation is passed, infer from the description.
|
|
106
|
+
// Free reads: READ_TOOL (idempotent). Paid reads (description mentions
|
|
107
|
+
// "Costs N credit"): PREMIUM_READ_TOOL (NOT idempotent, because each
|
|
108
|
+
// call burns a credit and naive retry would double-charge). Tools that
|
|
109
|
+
// mutate (create_*_watch / delete_watch) pass CREATE_TOOL / DELETE_TOOL
|
|
110
|
+
// explicitly and bypass this inference.
|
|
111
|
+
const finalAnnotations = annotations ?? (PAID_TOOL_RE.test(description) ? PREMIUM_READ_TOOL : READ_TOOL);
|
|
94
112
|
const wrapped = (async (args, extra) => {
|
|
95
113
|
const result = await cb(args, extra);
|
|
96
114
|
return sanitizeToolResponse(result);
|
|
97
115
|
});
|
|
98
116
|
// Direct dispatch to the SDK's underlying registration. Do not call
|
|
99
117
|
// registerTool() here or it will recurse forever.
|
|
100
|
-
return server.tool(name, description, paramsSchema,
|
|
118
|
+
return server.tool(name, description, paramsSchema, finalAnnotations, wrapped);
|
|
101
119
|
}
|
|
120
|
+
// ── Resource: tensorfeed://news (latest 20 AI articles) ─────────────
|
|
121
|
+
// MCP's `resources` primitive is a parallel surface to tools. Hosts can
|
|
122
|
+
// list resources, subscribe to them, and fetch them by URI without going
|
|
123
|
+
// through the tool-call decision loop. We expose the latest news as a
|
|
124
|
+
// resource AS WELL AS the get_ai_news tool, so clients that prefer
|
|
125
|
+
// data-shaped surfaces (Claude Desktop, some agent frameworks) can attach
|
|
126
|
+
// the news feed directly. Same upstream endpoint; different MCP primitive.
|
|
127
|
+
server.registerResource('latest_news', 'tensorfeed://news/latest', {
|
|
128
|
+
description: 'Latest 20 AI news articles aggregated by TensorFeed.ai. Refreshed every ~10 minutes from 15+ sources (Anthropic, OpenAI, Google, TechCrunch, The Verge, arXiv, and more). Each row carries title, source, URL, snippet, categories, and publication timestamp. JSON payload. Refresh on `resources/read`; no subscription required.',
|
|
129
|
+
mimeType: 'application/json',
|
|
130
|
+
}, async (uri) => {
|
|
131
|
+
const data = (await fetchJSON('/news?limit=20'));
|
|
132
|
+
return {
|
|
133
|
+
contents: [
|
|
134
|
+
{
|
|
135
|
+
uri: uri.toString(),
|
|
136
|
+
mimeType: 'application/json',
|
|
137
|
+
text: JSON.stringify({
|
|
138
|
+
source: 'TensorFeed.ai',
|
|
139
|
+
fetched_at: new Date().toISOString(),
|
|
140
|
+
count: data.articles.length,
|
|
141
|
+
articles: data.articles,
|
|
142
|
+
}, null, 2),
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
});
|
|
102
147
|
// ── Tool: get_ai_news ───────────────────────────────────────────────
|
|
103
148
|
registerTool('get_ai_news', 'Get the latest AI news articles from TensorFeed.ai. Aggregates from 15+ sources including Anthropic, OpenAI, Google, TechCrunch, The Verge, arXiv, and more.', {
|
|
104
149
|
category: z.string().optional().describe('Filter by category (e.g. "anthropic", "openai", "research", "tools")'),
|
|
@@ -323,6 +368,114 @@ registerTool('get_ai_supply_chain_iocs', 'Get the latest AI/ML supply-chain indi
|
|
|
323
368
|
const footer = `\n\nPosture: ${data.posture}`;
|
|
324
369
|
return { content: [{ type: 'text', text: `${header}\n\n${body}${footer}` }] };
|
|
325
370
|
});
|
|
371
|
+
// ── Tool: get_honeypot_iocs ─────────────────────────────────────────
|
|
372
|
+
registerTool('get_honeypot_iocs', 'Get the TensorFeed honeypot indicators-of-compromise feed. Returns attacker IP addresses, user agents, and target paths observed against TensorFeed.ai trap endpoints over the last 30 days. Pure first-party observation; not a re-export of upstream threat intel. License CC0; downstream defenders may ingest and pre-block at their edge. Each row: ioc value, ioc type (ip / ua / path), first_seen, last_seen, hit_count. Useful as a low-noise honeypot signal layered on top of public IOC feeds.', {
|
|
373
|
+
type: z
|
|
374
|
+
.enum(['ip', 'ua', 'path'])
|
|
375
|
+
.optional()
|
|
376
|
+
.describe('Filter to one IOC type. Omit to return all types.'),
|
|
377
|
+
limit: z
|
|
378
|
+
.number()
|
|
379
|
+
.min(1)
|
|
380
|
+
.max(500)
|
|
381
|
+
.optional()
|
|
382
|
+
.describe('Maximum number of IOCs to return (default 50, max 500)'),
|
|
383
|
+
}, async ({ type, limit }) => {
|
|
384
|
+
const data = (await fetchJSON('/security/iocs.json'));
|
|
385
|
+
const typeWanted = type?.toLowerCase();
|
|
386
|
+
const filtered = data.iocs.filter((e) => !typeWanted || e.type.toLowerCase() === typeWanted);
|
|
387
|
+
const cap = Math.min(limit ?? 50, 500);
|
|
388
|
+
const rows = filtered.slice(0, cap);
|
|
389
|
+
if (rows.length === 0) {
|
|
390
|
+
return {
|
|
391
|
+
content: [
|
|
392
|
+
{
|
|
393
|
+
type: 'text',
|
|
394
|
+
text: `No honeypot IOCs matched (total in feed: ${data.total_iocs}, window ${data.window_hours}h, generated ${data.generated_at}).`,
|
|
395
|
+
},
|
|
396
|
+
],
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
const body = rows
|
|
400
|
+
.map((e, i) => `${i + 1}. [${e.type}] ${e.ioc}\n hits: ${e.hit_count} first: ${e.first_seen} last: ${e.last_seen}`)
|
|
401
|
+
.join('\n');
|
|
402
|
+
const header = `TensorFeed honeypot IOCs (${rows.length} of ${filtered.length} matched, ${data.total_iocs} in feed, ${data.window_hours}h window, generated ${data.generated_at}):`;
|
|
403
|
+
const footer = `\n\nLicense: ${data.policy.license}. ${data.policy.description}`;
|
|
404
|
+
return { content: [{ type: 'text', text: `${header}\n\n${body}${footer}` }] };
|
|
405
|
+
});
|
|
406
|
+
// ── Tool: check_afta_certification ──────────────────────────────────
|
|
407
|
+
registerTool('check_afta_certification', 'Check whether a domain is AFTA-certified (Agent Fair-Trade Agreement). AFTA is an open standard: cryptographically-signed receipts, transparent pricing, no-charge guarantees for failed responses, on-chain settlement, and federated trust between participating sites. The check runs 6 deterministic probes against the target domain (e.g. tensorfeed.ai, terminalfeed.io): well-known endpoint, receipts endpoint, x402 payment manifest, pricing transparency, free trial availability, federation membership. Returns score, verdict, and which checks passed/failed.', {
|
|
408
|
+
domain: z
|
|
409
|
+
.string()
|
|
410
|
+
.describe('Domain to certify (e.g. "tensorfeed.ai", "terminalfeed.io"). Bare host, no protocol.'),
|
|
411
|
+
}, async ({ domain }) => {
|
|
412
|
+
const data = (await fetchJSON(`/afta-certify/check?domain=${encodeURIComponent(domain)}`));
|
|
413
|
+
const lines = data.checks.map((c) => ` ${c.passed ? 'PASS' : 'FAIL'} ${c.name}${c.details ? ` (${c.details})` : ''}`);
|
|
414
|
+
const certified = data.afta_certified ? 'AFTA-CERTIFIED' : 'NOT certified';
|
|
415
|
+
const next = data.next_step ? `\nNext step: ${data.next_step}` : '';
|
|
416
|
+
return {
|
|
417
|
+
content: [
|
|
418
|
+
{
|
|
419
|
+
type: 'text',
|
|
420
|
+
text: `Domain: ${data.domain}\nScore: ${data.score}/${data.max}\nVerdict: ${data.verdict} (${certified})\nChecked: ${data.checked_at}\n\nChecks:\n${lines.join('\n')}${next}`,
|
|
421
|
+
},
|
|
422
|
+
],
|
|
423
|
+
};
|
|
424
|
+
});
|
|
425
|
+
// ── Tool: get_agent_reputation_card ─────────────────────────────────
|
|
426
|
+
registerTool('get_agent_reputation_card', 'Get a TensorFeed Agent Reputation Bureau card for an EVM wallet address or a tf_live_ token prefix. Cards rebuild daily at 04:50 UTC from on-chain receipts plus TF telemetry. Includes reliability score, paid-call activity, total USDC spent, longest paid streak, composite trust score (0-1), trust grade (S/A/B/C/D), flags (sybil_risk, abuse, paid_free_ratio_low), operator-claim status (wallet -> display name signed by EOA), and per-metric leaderboard ranks. Returns null/404 for unknown agents (TF only builds cards for wallets observed in production). Useful for assessing third-party agent trustworthiness before delegating high-value work.', {
|
|
427
|
+
wallet: z
|
|
428
|
+
.string()
|
|
429
|
+
.optional()
|
|
430
|
+
.describe('EVM wallet address (0x... 42 chars). Provide either this OR token_prefix.'),
|
|
431
|
+
token_prefix: z
|
|
432
|
+
.string()
|
|
433
|
+
.optional()
|
|
434
|
+
.describe('First N chars of an agent\'s tf_live_ bearer token. Useful when the agent has not signed an operator-claim yet.'),
|
|
435
|
+
}, async ({ wallet, token_prefix }) => {
|
|
436
|
+
if (!wallet && !token_prefix) {
|
|
437
|
+
return {
|
|
438
|
+
content: [
|
|
439
|
+
{
|
|
440
|
+
type: 'text',
|
|
441
|
+
text: 'Provide either `wallet` (0x... EVM address) or `token_prefix` (tf_live_... token prefix). Both are accepted, one is required.',
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
const path = wallet
|
|
447
|
+
? `/agents/reputation/${encodeURIComponent(wallet)}`
|
|
448
|
+
: `/agents/reputation/by-token/${encodeURIComponent(token_prefix)}`;
|
|
449
|
+
let data;
|
|
450
|
+
try {
|
|
451
|
+
data = await fetchJSON(path);
|
|
452
|
+
}
|
|
453
|
+
catch (e) {
|
|
454
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
455
|
+
if (msg.includes('404') || msg.toLowerCase().includes('not_found')) {
|
|
456
|
+
return {
|
|
457
|
+
content: [
|
|
458
|
+
{
|
|
459
|
+
type: 'text',
|
|
460
|
+
text: `No reputation card for ${wallet ?? token_prefix}. TF only builds cards for wallets observed in production; if this is a real agent that has paid TF before, it should appear in the next daily rebuild (04:50 UTC).`,
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
throw e;
|
|
466
|
+
}
|
|
467
|
+
// The card schema is rich; render the highlights deterministically and
|
|
468
|
+
// include the raw JSON so the agent can reason over any field it needs.
|
|
469
|
+
const card = data.card ?? data;
|
|
470
|
+
return {
|
|
471
|
+
content: [
|
|
472
|
+
{
|
|
473
|
+
type: 'text',
|
|
474
|
+
text: `Agent reputation card for ${wallet ?? `token_prefix=${token_prefix}`}:\n\n${JSON.stringify(card, null, 2)}`,
|
|
475
|
+
},
|
|
476
|
+
],
|
|
477
|
+
};
|
|
478
|
+
});
|
|
326
479
|
// ════════════════════════════════════════════════════════════════════
|
|
327
480
|
// PREMIUM TOOLS (require TENSORFEED_TOKEN env var, paid in USDC on Base)
|
|
328
481
|
// ════════════════════════════════════════════════════════════════════
|
|
@@ -358,7 +511,7 @@ registerTool('get_account_usage', 'Show per-endpoint usage for the configured Te
|
|
|
358
511
|
};
|
|
359
512
|
});
|
|
360
513
|
// ── Tool: premium_routing (1 credit) ────────────────────────────────
|
|
361
|
-
registerTool('premium_routing', 'Get a ranked list of recommended AI models for a task with full score breakdown (quality, availability, cost, latency). Costs 1 credit.', {
|
|
514
|
+
registerTool('premium_routing', 'Get a ranked list of recommended AI models for a task with full score breakdown (quality, availability, cost, latency). Costs 1 credit ($0.02).', {
|
|
362
515
|
task: z.enum(['code', 'reasoning', 'creative', 'general']).optional().describe('Task type the model needs to be good at (default: general)'),
|
|
363
516
|
budget: z.number().optional().describe('Max blended USD per 1M tokens'),
|
|
364
517
|
min_quality: z.number().min(0).max(1).optional().describe('Minimum quality score in [0, 1]'),
|
|
@@ -475,7 +628,7 @@ registerTool('status_leaderboard_free', 'Cross-provider uptime leaderboard, rank
|
|
|
475
628
|
};
|
|
476
629
|
});
|
|
477
630
|
// ── Tool: pricing_series (1 credit) ─────────────────────────────────
|
|
478
|
-
registerTool('pricing_series', 'Daily price points for one AI model with min/max/delta summary. Default range = last 30 days, max 90 days. Costs 1 credit.', {
|
|
631
|
+
registerTool('pricing_series', 'Daily price points for one AI model with min/max/delta summary. Default range = last 30 days, max 90 days. Costs 1 credit ($0.02). Strict premium, no free trial; the 7-day-capped sibling pricing_series_free is the discovery option.', {
|
|
479
632
|
model: z.string().describe('Model id or display name (e.g. "Claude Opus 4.7" or "claude-opus-4-7")'),
|
|
480
633
|
from: z.string().optional().describe('Start date YYYY-MM-DD UTC (default: 30 days ago)'),
|
|
481
634
|
to: z.string().optional().describe('End date YYYY-MM-DD UTC (default: today)'),
|
|
@@ -500,7 +653,7 @@ registerTool('pricing_series', 'Daily price points for one AI model with min/max
|
|
|
500
653
|
};
|
|
501
654
|
});
|
|
502
655
|
// ── Tool: benchmark_series (1 credit) ───────────────────────────────
|
|
503
|
-
registerTool('benchmark_series', 'Score evolution for a single benchmark on one AI model. Costs 1 credit. Benchmark keys: swe_bench, mmlu_pro, gpqa_diamond, math, human_eval.', {
|
|
656
|
+
registerTool('benchmark_series', 'Score evolution for a single benchmark on one AI model. Costs 1 credit ($0.02). Strict premium, no free trial; the 7-day-capped sibling benchmark_series_free is the discovery option. Benchmark keys: swe_bench, mmlu_pro, gpqa_diamond, math, human_eval.', {
|
|
504
657
|
model: z.string().describe('Model id or display name'),
|
|
505
658
|
benchmark: z.string().describe('Benchmark key (e.g. swe_bench, mmlu_pro, gpqa_diamond, math, human_eval)'),
|
|
506
659
|
from: z.string().optional().describe('Start date YYYY-MM-DD UTC (default: 30 days ago)'),
|
|
@@ -526,7 +679,7 @@ registerTool('benchmark_series', 'Score evolution for a single benchmark on one
|
|
|
526
679
|
};
|
|
527
680
|
});
|
|
528
681
|
// ── Tool: status_uptime (1 credit) ──────────────────────────────────
|
|
529
|
-
registerTool('status_uptime', 'Daily uptime rollup for one provider with operational/degraded/down day counts and uptime % (degraded counts as half-credit). Costs 1 credit.', {
|
|
682
|
+
registerTool('status_uptime', 'Daily uptime rollup for one provider with operational/degraded/down day counts and uptime % (degraded counts as half-credit). Costs 1 credit ($0.02). Strict premium, no free trial; the 7-day-capped sibling status_uptime_free is the discovery option.', {
|
|
530
683
|
provider: z.string().describe('Provider name (e.g. anthropic, openai, google)'),
|
|
531
684
|
from: z.string().optional().describe('Start date YYYY-MM-DD UTC (default: 30 days ago)'),
|
|
532
685
|
to: z.string().optional().describe('End date YYYY-MM-DD UTC (default: today)'),
|
|
@@ -553,7 +706,7 @@ registerTool('status_uptime', 'Daily uptime rollup for one provider with operati
|
|
|
553
706
|
};
|
|
554
707
|
});
|
|
555
708
|
// ── Tool: status_leaderboard (1 credit) ─────────────────────────────
|
|
556
|
-
registerTool('status_leaderboard', 'Cross-provider uptime leaderboard for a custom date range up to 90 days. Same minute-resolution counter source as status_leaderboard_free, but adds incident_count and mttr_minutes (mean time to recover) per provider. Sorted by uptime % DESC. Costs 1 credit.', {
|
|
709
|
+
registerTool('status_leaderboard', 'Cross-provider uptime leaderboard for a custom date range up to 90 days. Same minute-resolution counter source as status_leaderboard_free, but adds incident_count and mttr_minutes (mean time to recover) per provider. Sorted by uptime % DESC. Costs 1 credit ($0.02). Strict premium, no free trial; the 7-day-capped sibling status_leaderboard_free is the discovery option.', {
|
|
557
710
|
from: z.string().optional().describe('Start date YYYY-MM-DD UTC (default: 30 days ago)'),
|
|
558
711
|
to: z.string().optional().describe('End date YYYY-MM-DD UTC (default: today)'),
|
|
559
712
|
}, async ({ from, to }) => {
|
|
@@ -579,7 +732,7 @@ registerTool('status_leaderboard', 'Cross-provider uptime leaderboard for a cust
|
|
|
579
732
|
};
|
|
580
733
|
});
|
|
581
734
|
// ── Tool: premium_agents_directory (1 credit) ───────────────────────
|
|
582
|
-
registerTool('premium_agents_directory', 'Enriched AI agents catalog joined with live status, recent news, agent traffic, flagship pricing, and a 0-100 trending_score. Costs 1 credit.', {
|
|
735
|
+
registerTool('premium_agents_directory', 'Enriched AI agents catalog joined with live status, recent news, agent traffic, flagship pricing, and a 0-100 trending_score. Costs 1 credit ($0.02).', {
|
|
583
736
|
category: z.string().optional().describe('coding, research, general, creative, frameworks'),
|
|
584
737
|
status: z.enum(['operational', 'degraded', 'down', 'unknown']).optional(),
|
|
585
738
|
open_source: z.boolean().optional(),
|
|
@@ -612,7 +765,7 @@ registerTool('premium_agents_directory', 'Enriched AI agents catalog joined with
|
|
|
612
765
|
};
|
|
613
766
|
});
|
|
614
767
|
// ── Tool: whats_new (1 credit) ──────────────────────────────────────
|
|
615
|
-
registerTool('whats_new', 'Agent morning brief: pricing changes, new/removed models, status incidents, and top news from the last 1-7 days. The tool to call when your agent boots up. Costs 1 credit.', {
|
|
768
|
+
registerTool('whats_new', 'Agent morning brief: pricing changes, new/removed models, status incidents, and top news from the last 1-7 days. The tool to call when your agent boots up. Costs 1 credit ($0.02).', {
|
|
616
769
|
days: z.number().min(1).max(7).optional().describe('Window length in days (default 1)'),
|
|
617
770
|
news_limit: z.number().min(1).max(25).optional().describe('Max news headlines (default 10)'),
|
|
618
771
|
}, async ({ days, news_limit }) => {
|
|
@@ -648,7 +801,7 @@ registerTool('whats_new', 'Agent morning brief: pricing changes, new/removed mod
|
|
|
648
801
|
};
|
|
649
802
|
});
|
|
650
803
|
// ── Tool: compare_models (1 credit) ─────────────────────────────────
|
|
651
|
-
registerTool('compare_models', 'Side-by-side comparison of 2-5 AI models. Returns pricing, benchmarks (normalized to a union of keys with null for missing scores), provider status, and recent news per model, plus rankings (cheapest blended, most context, per-benchmark leaderboard). Costs 1 credit.', {
|
|
804
|
+
registerTool('compare_models', 'Side-by-side comparison of 2-5 AI models. Returns pricing, benchmarks (normalized to a union of keys with null for missing scores), provider status, and recent news per model, plus rankings (cheapest blended, most context, per-benchmark leaderboard). Costs 1 credit ($0.02).', {
|
|
652
805
|
ids: z.string().describe('Comma-separated list of 2-5 model ids or display names. Examples: "Claude Opus 4.7,GPT-5.5,Gemini 3" or "opus-4-7,gpt-5-5"'),
|
|
653
806
|
}, async ({ ids }) => {
|
|
654
807
|
const data = (await fetchJSON(`/premium/compare/models?ids=${encodeURIComponent(ids)}`, { auth: true }));
|
|
@@ -675,7 +828,7 @@ registerTool('compare_models', 'Side-by-side comparison of 2-5 AI models. Return
|
|
|
675
828
|
};
|
|
676
829
|
});
|
|
677
830
|
// ── Tool: provider_deepdive (1 credit) ──────────────────────────────
|
|
678
|
-
registerTool('provider_deepdive', 'Everything about an AI provider in one call: live status, all models with pricing + tier + benchmark scores joined in, recent news mentions, and agent traffic. Costs 1 credit. Aggregation IS the value; doing this from free endpoints would take 4 round-trips.', {
|
|
831
|
+
registerTool('provider_deepdive', 'Everything about an AI provider in one call: live status, all models with pricing + tier + benchmark scores joined in, recent news mentions, and agent traffic. Costs 1 credit ($0.02). Strict premium, no free trial. Aggregation IS the value; doing this from free endpoints would take 4 round-trips.', {
|
|
679
832
|
provider: z.string().describe('Provider id or display name (case-insensitive). Examples: anthropic, openai, google, mistral, cohere'),
|
|
680
833
|
}, async ({ provider }) => {
|
|
681
834
|
const data = (await fetchJSON(`/premium/providers/${encodeURIComponent(provider)}`, { auth: true }));
|
|
@@ -705,7 +858,7 @@ registerTool('provider_deepdive', 'Everything about an AI provider in one call:
|
|
|
705
858
|
};
|
|
706
859
|
});
|
|
707
860
|
// ── Tool: cost_projection (1 credit) ────────────────────────────────
|
|
708
|
-
registerTool('cost_projection', 'Project the cost of a token-usage workload across 1-10 AI models. Returns daily/weekly/monthly/yearly totals per model and a ranking by cheapest monthly. Costs 1 credit.', {
|
|
861
|
+
registerTool('cost_projection', 'Project the cost of a token-usage workload across 1-10 AI models. Returns daily/weekly/monthly/yearly totals per model and a ranking by cheapest monthly. Costs 1 credit ($0.02).', {
|
|
709
862
|
models: z.string().describe('One model or comma-separated list of up to 10 (e.g. "Claude Opus 4.7,GPT-5.5,Gemini 3"). Names or ids both work.'),
|
|
710
863
|
input_tokens_per_day: z.number().min(0).describe('Expected daily input token volume'),
|
|
711
864
|
output_tokens_per_day: z.number().min(0).describe('Expected daily output token volume'),
|
|
@@ -740,7 +893,7 @@ registerTool('cost_projection', 'Project the cost of a token-usage workload acro
|
|
|
740
893
|
};
|
|
741
894
|
});
|
|
742
895
|
// ── Tool: news_search (1 credit) ────────────────────────────────────
|
|
743
|
-
registerTool('news_search', 'Full-text search over the TensorFeed news article corpus with optional date range, provider, and category filters. Relevance scoring with recency boost. Costs 1 credit.', {
|
|
896
|
+
registerTool('news_search', 'Full-text search over the TensorFeed news article corpus with optional date range, provider, and category filters. Relevance scoring with recency boost. Costs 1 credit ($0.02).', {
|
|
744
897
|
q: z.string().optional().describe('Free-text query, e.g. "claude opus pricing". Omit to browse latest filtered articles.'),
|
|
745
898
|
from: z.string().optional().describe('Start date YYYY-MM-DD UTC (inclusive)'),
|
|
746
899
|
to: z.string().optional().describe('End date YYYY-MM-DD UTC (inclusive end-of-day)'),
|
|
@@ -794,7 +947,7 @@ registerTool('list_watches', 'List the active webhook watches owned by the confi
|
|
|
794
947
|
return { content: [{ type: 'text', text: `${data.count} active watches:\n\n${rows}` }] };
|
|
795
948
|
});
|
|
796
949
|
// ── Tool: create_price_watch (1 credit) ─────────────────────────────
|
|
797
|
-
registerTool('create_price_watch', 'Register a webhook watch on a model price change. Costs 1 credit. Watch lives 90 days. Each fire is an HMAC-signed POST to callback_url.', {
|
|
950
|
+
registerTool('create_price_watch', 'Register a webhook watch on a model price change. Costs 1 credit ($0.02). Watch lives 90 days. Each fire is an HMAC-signed POST to callback_url.', {
|
|
798
951
|
model: z.string().describe('Model name (e.g. "Claude Opus 4.7")'),
|
|
799
952
|
field: z.enum(['inputPrice', 'outputPrice', 'blended']).describe('Which price field to watch'),
|
|
800
953
|
op: z.enum(['lt', 'gt', 'changes']).describe('Trigger: lt = below threshold, gt = above, changes = any change'),
|
|
@@ -819,7 +972,7 @@ registerTool('create_price_watch', 'Register a webhook watch on a model price ch
|
|
|
819
972
|
};
|
|
820
973
|
}, CREATE_TOOL);
|
|
821
974
|
// ── Tool: create_status_watch (1 credit) ────────────────────────────
|
|
822
|
-
registerTool('create_status_watch', 'Register a webhook watch on a service status transition (e.g. anthropic becomes down). Costs 1 credit. Watch lives 90 days.', {
|
|
975
|
+
registerTool('create_status_watch', 'Register a webhook watch on a service status transition (e.g. anthropic becomes down). Costs 1 credit ($0.02). Watch lives 90 days.', {
|
|
823
976
|
provider: z.string().describe('Provider name (e.g. anthropic, openai)'),
|
|
824
977
|
op: z.enum(['becomes', 'changes']).describe('becomes = transitions to a specific value; changes = any transition'),
|
|
825
978
|
value: z.enum(['operational', 'degraded', 'down']).optional().describe('Required when op is becomes'),
|
|
@@ -843,7 +996,7 @@ registerTool('create_status_watch', 'Register a webhook watch on a service statu
|
|
|
843
996
|
};
|
|
844
997
|
}, CREATE_TOOL);
|
|
845
998
|
// ── Tool: create_digest_watch (1 credit) ────────────────────────────
|
|
846
|
-
registerTool('create_digest_watch', 'Register a scheduled digest webhook that fires daily or weekly with a curated summary of pricing changes (regardless of whether anything dramatic happened). Costs 1 credit. Watch lives 90 days. Set-and-forget for agents that want a periodic snapshot without subscribing to realtime transitions.', {
|
|
999
|
+
registerTool('create_digest_watch', 'Register a scheduled digest webhook that fires daily or weekly with a curated summary of pricing changes (regardless of whether anything dramatic happened). Costs 1 credit ($0.02). Watch lives 90 days. Set-and-forget for agents that want a periodic snapshot without subscribing to realtime transitions.', {
|
|
847
1000
|
cadence: z.enum(['daily', 'weekly']).describe('How often the digest fires'),
|
|
848
1001
|
callback_url: z.string().describe('HTTPS URL to POST to when the digest fires'),
|
|
849
1002
|
secret: z.string().optional().describe('Optional HMAC shared secret'),
|
|
@@ -865,7 +1018,7 @@ registerTool('create_digest_watch', 'Register a scheduled digest webhook that fi
|
|
|
865
1018
|
};
|
|
866
1019
|
}, CREATE_TOOL);
|
|
867
1020
|
// ── Tool: create_leaderboard_rank_watch (1 credit) ──────────────────
|
|
868
|
-
registerTool('create_leaderboard_rank_watch', 'Register a webhook that fires when a provider crosses a rank threshold on the cross-provider 7-day uptime leaderboard. Rank 1 = best (highest uptime). drops_below: was rank<=N, now rank>N (got worse). rises_above: was rank>=N, now rank<N (got better). changes: any rank movement. Costs 1 credit at registration. Watch lives 90 days.', {
|
|
1021
|
+
registerTool('create_leaderboard_rank_watch', 'Register a webhook that fires when a provider crosses a rank threshold on the cross-provider 7-day uptime leaderboard. Rank 1 = best (highest uptime). drops_below: was rank<=N, now rank>N (got worse). rises_above: was rank>=N, now rank<N (got better). changes: any rank movement. Costs 1 credit ($0.02) at registration. Watch lives 90 days.', {
|
|
869
1022
|
provider: z.string().describe('Provider name or slug (case-insensitive). e.g. claude, openai, gemini, bedrock, azure'),
|
|
870
1023
|
op: z.enum(['drops_below', 'rises_above', 'changes']).describe('Trigger condition'),
|
|
871
1024
|
threshold: z.number().int().min(1).optional().describe('Required for drops_below / rises_above. Integer rank position.'),
|
|
@@ -925,7 +1078,7 @@ registerTool('probe_latest', 'Last 24 hours of measured LLM endpoint latency and
|
|
|
925
1078
|
};
|
|
926
1079
|
});
|
|
927
1080
|
// ── Tool: probe_series (1 credit) ───────────────────────────────────
|
|
928
|
-
registerTool('probe_series', 'Daily SLA series for one LLM provider, measured by TensorFeed. Returns per-day count, success rate, ttfb p50/p95/p99, total p50/p95/p99, and incident-hour count across the requested window. Provider status pages are politically managed; this is the measured truth. Pairs naturally with premium_routing for picking a model whose SLA you can verify. Costs 1 credit.', {
|
|
1081
|
+
registerTool('probe_series', 'Daily SLA series for one LLM provider, measured by TensorFeed. Returns per-day count, success rate, ttfb p50/p95/p99, total p50/p95/p99, and incident-hour count across the requested window. Provider status pages are politically managed; this is the measured truth. Pairs naturally with premium_routing for picking a model whose SLA you can verify. Costs 1 credit ($0.02). Strict premium, no free trial.', {
|
|
929
1082
|
provider: z.enum(['anthropic', 'openai', 'google', 'mistral', 'cohere']).describe('LLM provider key'),
|
|
930
1083
|
from: z.string().optional().describe('Inclusive start YYYY-MM-DD (default: 30 days before to)'),
|
|
931
1084
|
to: z.string().optional().describe('Inclusive end YYYY-MM-DD (default: today UTC)'),
|
|
@@ -987,7 +1140,7 @@ registerTool('mcp_registry_snapshot', 'Today\'s summary of the official Model Co
|
|
|
987
1140
|
};
|
|
988
1141
|
});
|
|
989
1142
|
// ── Tool: mcp_registry_series (1 credit) ────────────────────────────
|
|
990
|
-
registerTool('mcp_registry_series', 'Multi-day series of MCP server registry growth and churn. Returns per-day total servers, active count, and daily added/removed counts across the requested window. The registry itself is open data, but a 30/90-day trend requires daily capture started weeks ago, which TensorFeed has been running. Costs 1 credit.', {
|
|
1143
|
+
registerTool('mcp_registry_series', 'Multi-day series of MCP server registry growth and churn. Returns per-day total servers, active count, and daily added/removed counts across the requested window. The registry itself is open data, but a 30/90-day trend requires daily capture started weeks ago, which TensorFeed has been running. Costs 1 credit ($0.02).', {
|
|
991
1144
|
from: z.string().optional().describe('Inclusive start date YYYY-MM-DD (default: 30 days before to)'),
|
|
992
1145
|
to: z.string().optional().describe('Inclusive end date YYYY-MM-DD (default: today UTC)'),
|
|
993
1146
|
}, async ({ from, to }) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tensorfeed/mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.30.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",
|