@tensorfeed/mcp-server 1.23.0 → 1.25.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,16 @@
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.25.0 - 2026-05-06
6
+
7
+ ### Added
8
+ - Tool annotations on every registered tool (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`). All `get_*`, `*_series`, `*_search`, `compare_*`, `provider_deepdive`, `cost_projection`, `whats_new`, `*_snapshot`, `probe_*`, `list_watches`, `premium_routing`, and `premium_agents_directory` tools are flagged read-only + idempotent + open-world. The four `create_*_watch` tools are flagged write + non-idempotent. `delete_watch` is flagged destructive + idempotent. Hosts and clients can now decide whether a tool is safe to batch, retry, or call autonomously without re-prompting the user. Required by the Anthropic Connectors Directory.
9
+
10
+ ## 1.24.0 - 2026-05-06
11
+
12
+ ### Added
13
+ - `get_model_deprecations` tool (free). Wraps the new `/api/model-deprecations` endpoint. Returns the provider-by-provider model retirement and deprecation calendar with announced / deprecation / sunset dates, recommended replacement model id, and a source URL pointing at the provider's own announcement. Optional `provider` and `status` filters. Agents that depend on a specific model id can now ask one question and learn whether the model will keep accepting traffic and, if not, what to migrate to. Closes the most-frequent agent-operator surprise in the production lifecycle.
14
+
5
15
  ## 1.23.0 - 2026-05-05
6
16
 
7
17
  ### Added
package/dist/index.js CHANGED
@@ -56,14 +56,44 @@ const server = new McpServer({
56
56
  // covers any new endpoint that might forget it, plus protects against
57
57
  // drift between worker rules and what the MCP server should consider
58
58
  // safe. See ./sanitize.ts.
59
- function registerTool(name, description, paramsSchema, cb) {
59
+ // MCP tool annotation presets. These are HINTS for hosts/clients and agents
60
+ // so they can decide whether a tool is safe to call autonomously, batch, or
61
+ // retry. Required by the Anthropic Connectors Directory and used by client
62
+ // tool-pickers. See https://modelcontextprotocol.io/specification#tool-annotations
63
+ //
64
+ // readOnlyHint: true if the tool only reads, no side effects on the world
65
+ // destructiveHint: true if the tool may delete/destroy data
66
+ // idempotentHint: true if calling twice has the same effect as once
67
+ // openWorldHint: true if the tool interacts with external systems (HTTP/APIs)
68
+ //
69
+ // All TensorFeed tools hit the tensorfeed.ai HTTP API, so openWorldHint is
70
+ // always true here.
71
+ const READ_TOOL = {
72
+ readOnlyHint: true,
73
+ destructiveHint: false,
74
+ idempotentHint: true,
75
+ openWorldHint: true,
76
+ };
77
+ const CREATE_TOOL = {
78
+ readOnlyHint: false,
79
+ destructiveHint: false,
80
+ idempotentHint: false,
81
+ openWorldHint: true,
82
+ };
83
+ const DELETE_TOOL = {
84
+ readOnlyHint: false,
85
+ destructiveHint: true,
86
+ idempotentHint: true,
87
+ openWorldHint: true,
88
+ };
89
+ function registerTool(name, description, paramsSchema, cb, annotations = READ_TOOL) {
60
90
  const wrapped = (async (args, extra) => {
61
91
  const result = await cb(args, extra);
62
92
  return sanitizeToolResponse(result);
63
93
  });
64
94
  // Direct dispatch to the SDK's underlying registration. Do not call
65
95
  // registerTool() here or it will recurse forever.
66
- return server.tool(name, description, paramsSchema, wrapped);
96
+ return server.tool(name, description, paramsSchema, annotations, wrapped);
67
97
  }
68
98
  // ── Tool: get_ai_news ───────────────────────────────────────────────
69
99
  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.', {
@@ -134,6 +164,66 @@ registerTool('get_model_pricing', 'Get AI model pricing comparison across all ma
134
164
  .join('\n\n');
135
165
  return { content: [{ type: 'text', text: `AI Model Pricing (per 1M tokens):\n\n${text}` }] };
136
166
  });
167
+ // ── Tool: get_model_deprecations ────────────────────────────────────
168
+ registerTool('get_model_deprecations', "Get the AI model deprecation calendar. Provider-by-provider registry of model retirements and deprecation announcements (OpenAI, Anthropic, Google, Cohere, and others). Each entry carries the announced/deprecation/sunset dates, the recommended replacement model, and a source URL pointing at the provider's own announcement. Useful for agents who need to know when a model they depend on will stop accepting traffic and what to migrate to.", {
169
+ provider: z
170
+ .string()
171
+ .optional()
172
+ .describe('Filter to a single provider (e.g. "OpenAI", "Anthropic", "Google", "Cohere"). Case-insensitive.'),
173
+ status: z
174
+ .enum(['announced', 'deprecated', 'sunsetted'])
175
+ .optional()
176
+ .describe('Filter by lifecycle stage. announced = deprecation announced but model still serves at full capacity; deprecated = past deprecation date, migration required; sunsetted = no longer accepts traffic.'),
177
+ }, async ({ provider, status }) => {
178
+ const params = new URLSearchParams();
179
+ if (provider)
180
+ params.set('provider', provider);
181
+ if (status)
182
+ params.set('status', status);
183
+ const qs = params.toString();
184
+ const data = await fetchJSON(`/model-deprecations${qs ? `?${qs}` : ''}`);
185
+ const entries = data.deprecations ?? [];
186
+ if (entries.length === 0) {
187
+ return {
188
+ content: [
189
+ {
190
+ type: 'text',
191
+ text: 'No model deprecations matched the filter. The full calendar is at https://tensorfeed.ai/model-deprecations.',
192
+ },
193
+ ],
194
+ };
195
+ }
196
+ // Group by provider for readable output.
197
+ const byProvider = new Map();
198
+ for (const d of entries) {
199
+ const list = byProvider.get(d.provider) ?? [];
200
+ list.push(d);
201
+ byProvider.set(d.provider, list);
202
+ }
203
+ const sections = Array.from(byProvider.entries())
204
+ .sort(([a], [b]) => a.localeCompare(b))
205
+ .map(([prov, list]) => {
206
+ const rows = list
207
+ .map(d => {
208
+ const dates = [
209
+ d.announcedDate ? `announced ${d.announcedDate}` : null,
210
+ d.deprecationDate ? `deprecated ${d.deprecationDate}` : null,
211
+ d.sunsetDate ? `sunset ${d.sunsetDate}` : null,
212
+ ]
213
+ .filter(Boolean)
214
+ .join(', ');
215
+ const display = d.modelDisplay ? ` (${d.modelDisplay})` : '';
216
+ const repl = d.replacement ? `\n replacement: ${d.replacement}` : '';
217
+ const note = d.notes ? `\n note: ${d.notes}` : '';
218
+ return ` ${d.model}${display} [${d.status.toUpperCase()}]\n ${dates}${repl}${note}\n source: ${d.sourceUrl}`;
219
+ })
220
+ .join('\n');
221
+ return `${prov}:\n${rows}`;
222
+ })
223
+ .join('\n\n');
224
+ const header = `AI Model Deprecation Calendar (${entries.length} ${entries.length === 1 ? 'entry' : 'entries'}, last updated ${data.lastUpdated ?? 'recently'}):\n\n`;
225
+ return { content: [{ type: 'text', text: header + sections }] };
226
+ });
137
227
  // ── Tool: get_ai_today ──────────────────────────────────────────────
138
228
  registerTool('get_ai_today', 'Get a summary of what happened in AI today. Returns the top stories from the last 24 hours.', {
139
229
  limit: z.number().min(1).max(20).optional().describe('Number of stories (default 5)'),
@@ -667,7 +757,7 @@ registerTool('create_price_watch', 'Register a webhook watch on a model price ch
667
757
  },
668
758
  ],
669
759
  };
670
- });
760
+ }, CREATE_TOOL);
671
761
  // ── Tool: create_status_watch (1 credit) ────────────────────────────
672
762
  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.', {
673
763
  provider: z.string().describe('Provider name (e.g. anthropic, openai)'),
@@ -691,7 +781,7 @@ registerTool('create_status_watch', 'Register a webhook watch on a service statu
691
781
  },
692
782
  ],
693
783
  };
694
- });
784
+ }, CREATE_TOOL);
695
785
  // ── Tool: create_digest_watch (1 credit) ────────────────────────────
696
786
  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.', {
697
787
  cadence: z.enum(['daily', 'weekly']).describe('How often the digest fires'),
@@ -713,7 +803,7 @@ registerTool('create_digest_watch', 'Register a scheduled digest webhook that fi
713
803
  },
714
804
  ],
715
805
  };
716
- });
806
+ }, CREATE_TOOL);
717
807
  // ── Tool: create_leaderboard_rank_watch (1 credit) ──────────────────
718
808
  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.', {
719
809
  provider: z.string().describe('Provider name or slug (case-insensitive). e.g. claude, openai, gemini, bedrock, azure'),
@@ -740,14 +830,14 @@ registerTool('create_leaderboard_rank_watch', 'Register a webhook that fires whe
740
830
  },
741
831
  ],
742
832
  };
743
- });
833
+ }, CREATE_TOOL);
744
834
  // ── Tool: delete_watch ──────────────────────────────────────────────
745
835
  registerTool('delete_watch', 'Delete one of your active webhook watches by id. Free, requires TENSORFEED_TOKEN.', {
746
836
  watch_id: z.string().describe('The wat_... id from create_price_watch / create_status_watch / list_watches'),
747
837
  }, async ({ watch_id }) => {
748
838
  await fetchJSON(`/premium/watches/${watch_id}`, { method: 'DELETE', auth: true });
749
839
  return { content: [{ type: 'text', text: `Deleted watch ${watch_id}.` }] };
750
- });
840
+ }, DELETE_TOOL);
751
841
  // ── Tool: probe_latest (free) ───────────────────────────────────────
752
842
  registerTool('probe_latest', 'Last 24 hours of measured LLM endpoint latency and availability per provider (Anthropic, OpenAI, Google, Mistral, Cohere). TensorFeed pings each provider\'s chat completion endpoint every 15 min and records time-to-first-byte, total response time, and HTTP status. Returns per-provider success rate and ttfb/total p50/p95/p99 latency. The data is unique because we measure it ourselves, not self-reported by the providers. Useful when an agent needs to pick a provider whose SLA you can verify, or to detect ongoing incidents before they hit a status page. Free, no auth.', {}, async () => {
753
843
  const data = (await fetchJSON('/probe/latest'));
@@ -826,7 +916,7 @@ registerTool('mcp_registry_snapshot', 'Today\'s summary of the official Model Co
826
916
  content: [
827
917
  {
828
918
  type: 'text',
829
- text: `MCP Server Registry — ${s.date}\n` +
919
+ text: `MCP Server Registry, ${s.date}\n` +
830
920
  `Total servers: ${s.total_servers} (across ${s.total_versions} versioned entries)\n` +
831
921
  `Status: ${statusLine}\n${delta}\n\n` +
832
922
  `Top namespaces:\n${topNs}` +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tensorfeed/mcp-server",
3
- "version": "1.23.0",
3
+ "version": "1.25.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.23.0",
6
+ "version": "1.25.0",
7
7
  "websiteUrl": "https://tensorfeed.ai/developers/agent-payments",
8
8
  "repository": {
9
9
  "url": "https://github.com/RipperMercs/tensorfeed-mcp",
@@ -14,7 +14,7 @@
14
14
  "registryType": "npm",
15
15
  "registryBaseUrl": "https://registry.npmjs.org",
16
16
  "identifier": "@tensorfeed/mcp-server",
17
- "version": "1.23.0",
17
+ "version": "1.25.0",
18
18
  "runtimeHint": "npx",
19
19
  "transport": {
20
20
  "type": "stdio"