@pipeworx/mcp-newsdata 0.1.4 → 0.1.5

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/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  NewsData.io MCP — wraps the NewsData.io global news API (newsdata.io)
4
4
 
5
- Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 1684+ live data sources.
5
+ Part of [Pipeworx](https://pipeworx.io) — an MCP gateway connecting AI agents to 1764+ live data sources. This is an independent, unofficial integration — not affiliated with, endorsed by, or published by the upstream provider.
6
6
 
7
7
  ## Tools
8
8
 
9
9
  | Tool | Description |
10
10
  |------|-------------|
11
- | `latest_news` | Get the latest global news headlines and articles — world news, breaking news, and business/financial/stock-market news. Filter by keyword, country (2-letter, e.g. "us"), category (business, technology, politics, sports, health, science), and language. IMPORTANT: for stock-market / financial-market / economy / "world market news" questions, ALWAYS pass category: "business" — it returns real market-news outlets and filters out low-quality SEO/crypto-promo articles. Returns article title, description, link, source, publish date, category, and country. Paginate via the nextPage token. Examples: latest_news({ query: "stock market", category: "business" }) for world market news; latest_news({ query: "election", country: "us", category: "politics" }). |
11
+ | `latest_news` | Get news headlines and articles — world news, breaking news, and business/financial/stock-market news. Filter by keyword, country (2-letter, e.g. "us"), category (business, technology, politics, sports, health, science), and language. IMPORTANT: for stock-market / financial-market / economy / "world market news" questions, ALWAYS pass category: "business" — it returns real market-news outlets and filters out low-quality SEO/crypto-promo articles. Returns article title, description, link, source, publish date, category, and country. Paginate via the nextPage token. WITHOUT from_date/to_date this covers only roughly the LAST 48 HOURS (NewsData.io's rolling "latest" feed) — asking about an older event with no date window silently returns today's unrelated articles instead of an empty result. For a PAST date range, pass from_date/to_date (YYYY-MM-DD): this routes to NewsData.io's archive endpoint, which requires a plan tier above the shared platform key's default — if the account cannot serve it, the call returns a `filter_gap` field naming the unsupported window instead of silently substituting the latest 48h. Examples: latest_news({ query: "stock market", category: "business" }) for current world market news; latest_news({ query: "election", country: "us", category: "politics" }); latest_news({ query: "Houthi Yemen attack", from_date: "2026-08-01", to_date: "2026-08-15" }) for an August event. |
12
12
  | `crypto_news` | Get the latest cryptocurrency news headlines and articles. Filter by keyword, coin ticker(s) (e.g. "btc,eth"), and language. Returns article title, description, link, source, publish date, category, and country. Example: crypto_news({ coin: "btc,eth", query: "etf" }) |
13
13
  | `news_sources` | List available global news sources. Filter by country (2-letter), category, and language. Returns source id, name, url, category, country, and language — useful for discovering which outlets cover a given region or topic. Example: news_sources({ country: "us", category: "technology" }) |
14
14
 
@@ -56,7 +56,7 @@ directly, instead of just this one's:
56
56
  }
57
57
  ```
58
58
 
59
- Both URLs reach the same gateway and the same 1684+ data sources. The
59
+ Both URLs reach the same gateway and the same 1764+ data sources. The
60
60
  only difference is which pack's tools are listed **directly**; `ask_pipeworx`
61
61
  reaches all of them from either one.
62
62
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipeworx/mcp-newsdata",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "NewsData.io MCP — wraps the NewsData.io global news API (newsdata.io)",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -26,7 +26,7 @@
26
26
  "@cloudflare/workers-types": "^4.20260405.1"
27
27
  },
28
28
  "pipeworx": {
29
- "sourceHash": "v1-67e6f65fa18f2efea30dc86b384652fae8ea5e6cd116ea91615ad81be3fef742",
30
- "sourceCommit": "eaa02971997fbfee27712ea66d7d5fd840d008ea"
29
+ "sourceHash": "v1-31564baff3859f4b9d1dd873ff7eb95e691717035f02dd0a9a9ae9c0d9d1c492",
30
+ "sourceCommit": "0ce6905893fe8da0d285be2f05754a4200d67371"
31
31
  }
32
32
  }
package/server.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "io.github.pipeworx-io/newsdata",
4
4
  "title": "Newsdata",
5
5
  "description": "NewsData.io MCP — wraps the NewsData.io global news API (newsdata.io)",
6
- "version": "0.1.4",
6
+ "version": "0.1.5",
7
7
  "websiteUrl": "https://pipeworx.io/packs/newsdata",
8
8
  "repository": {
9
9
  "url": "https://github.com/pipeworx-io/mcp-newsdata",
package/src/index.ts CHANGED
@@ -699,7 +699,7 @@ const tools: McpToolExport['tools'] = [
699
699
  {
700
700
  name: 'latest_news',
701
701
  description:
702
- 'Get the latest global news headlines and articles — world news, breaking news, and business/financial/stock-market news. Filter by keyword, country (2-letter, e.g. "us"), category (business, technology, politics, sports, health, science), and language. IMPORTANT: for stock-market / financial-market / economy / "world market news" questions, ALWAYS pass category: "business" — it returns real market-news outlets and filters out low-quality SEO/crypto-promo articles. Returns article title, description, link, source, publish date, category, and country. Paginate via the nextPage token. Examples: latest_news({ query: "stock market", category: "business" }) for world market news; latest_news({ query: "election", country: "us", category: "politics" }).',
702
+ 'Get news headlines and articles — world news, breaking news, and business/financial/stock-market news. Filter by keyword, country (2-letter, e.g. "us"), category (business, technology, politics, sports, health, science), and language. IMPORTANT: for stock-market / financial-market / economy / "world market news" questions, ALWAYS pass category: "business" — it returns real market-news outlets and filters out low-quality SEO/crypto-promo articles. Returns article title, description, link, source, publish date, category, and country. Paginate via the nextPage token. WITHOUT from_date/to_date this covers only roughly the LAST 48 HOURS (NewsData.io\'s rolling "latest" feed) — asking about an older event with no date window silently returns today\'s unrelated articles instead of an empty result. For a PAST date range, pass from_date/to_date (YYYY-MM-DD): this routes to NewsData.io\'s archive endpoint, which requires a plan tier above the shared platform key\'s default — if the account cannot serve it, the call returns a `filter_gap` field naming the unsupported window instead of silently substituting the latest 48h. Examples: latest_news({ query: "stock market", category: "business" }) for current world market news; latest_news({ query: "election", country: "us", category: "politics" }); latest_news({ query: "Houthi Yemen attack", from_date: "2026-08-01", to_date: "2026-08-15" }) for an August event.',
703
703
  inputSchema: {
704
704
  type: 'object' as const,
705
705
  properties: {
@@ -719,6 +719,14 @@ const tools: McpToolExport['tools'] = [
719
719
  type: 'string',
720
720
  description: 'Language code to filter news by, e.g. "en", "es", "fr"',
721
721
  },
722
+ from_date: {
723
+ type: 'string',
724
+ description: 'Start of a PAST date window, YYYY-MM-DD. Supplying this (or to_date) switches the call from the 48h "latest" feed to NewsData.io\'s archive endpoint, which may require a higher plan tier than the shared platform key has — if so, the response carries `filter_gap` naming the unsupported window rather than silently returning current articles.',
725
+ },
726
+ to_date: {
727
+ type: 'string',
728
+ description: 'End of a PAST date window, YYYY-MM-DD. See from_date.',
729
+ },
722
730
  page: {
723
731
  type: 'string',
724
732
  description: 'nextPage token returned from a prior call, to fetch the next page of results',
@@ -862,6 +870,8 @@ const ARG_ALIASES: Record<string, readonly string[]> = {
862
870
  language: ['lang', 'languages', 'language_code'],
863
871
  coin: ['coins', 'ticker', 'tickers', 'symbol', 'symbols'],
864
872
  page: ['nextPage', 'next_page', 'page_token', 'pageToken', 'cursor'],
873
+ from_date: ['fromDate', 'start_date', 'startDate', 'since'],
874
+ to_date: ['toDate', 'end_date', 'endDate', 'until'],
865
875
  };
866
876
 
867
877
  /**
@@ -936,7 +946,7 @@ async function callTool(name: string, rawArgs: Record<string, unknown>): Promise
936
946
  }
937
947
 
938
948
  const ACCEPTED: Record<string, readonly string[]> = {
939
- latest_news: ['query', 'country', 'category', 'language', 'page'],
949
+ latest_news: ['query', 'country', 'category', 'language', 'page', 'from_date', 'to_date'],
940
950
  crypto_news: ['query', 'coin', 'language'],
941
951
  news_sources: ['country', 'category', 'language'],
942
952
  };
@@ -944,6 +954,51 @@ async function callTool(name: string, rawArgs: Record<string, unknown>): Promise
944
954
 
945
955
  switch (name) {
946
956
  case 'latest_news': {
957
+ const fromDate = args.from_date as string | undefined;
958
+ const toDate = args.to_date as string | undefined;
959
+
960
+ // A caller asking for a PAST window gets routed to NewsData.io's
961
+ // /archive endpoint instead of /latest (which only ever serves a
962
+ // rolling last-~48h feed and would otherwise silently answer an
963
+ // August question with October articles — fleet #2911, 7 judged
964
+ // misses on 3 questions). /archive commonly needs a plan tier above
965
+ // the shared platform key's default; rather than assume either way,
966
+ // make the live call and, if the upstream call itself fails (for ANY
967
+ // reason — a plan-tier rejection, an unsupported date range, a bad
968
+ // date format), DECLARE the gap instead of falling back to /latest,
969
+ // which would silently re-introduce exactly this bug.
970
+ if (fromDate || toDate) {
971
+ const archiveParams = new URLSearchParams();
972
+ if (args.query) archiveParams.set('q', args.query as string);
973
+ if (args.country) archiveParams.set('country', args.country as string);
974
+ if (args.category) archiveParams.set('category', args.category as string);
975
+ if (args.language) archiveParams.set('language', args.language as string);
976
+ if (fromDate) archiveParams.set('from_date', fromDate);
977
+ if (toDate) archiveParams.set('to_date', toDate);
978
+ if (args.page) archiveParams.set('page', args.page as string);
979
+
980
+ const archiveData = await newsdataGet(apiKey, '/archive', archiveParams);
981
+ const upstreamError =
982
+ archiveData && typeof archiveData === 'object' && 'error' in (archiveData as object)
983
+ ? (archiveData as { error: number; message: string })
984
+ : archiveData && typeof archiveData === 'object' && (archiveData as NewsListResponse).status === 'error'
985
+ ? { error: 'api_error', message: JSON.stringify(archiveData) }
986
+ : null;
987
+
988
+ if (upstreamError) {
989
+ return {
990
+ filter_gap: `date window (from_date=${fromDate ?? '(none)'}, to_date=${toDate ?? '(none)'}) could not be served — the archive endpoint call failed, most likely because this NewsData.io plan does not include dated/archive search`,
991
+ window_requested: { from_date: fromDate ?? null, to_date: toDate ?? null },
992
+ window_served: 'none — no fallback to the 48h latest feed was taken, to avoid silently answering a past-dated question with current articles',
993
+ upstream_error: upstreamError,
994
+ };
995
+ }
996
+ return {
997
+ window_requested: { from_date: fromDate ?? null, to_date: toDate ?? null },
998
+ ...mapArticles(archiveData as NewsListResponse),
999
+ };
1000
+ }
1001
+
947
1002
  const params = new URLSearchParams();
948
1003
  if (args.query) params.set('q', args.query as string);
949
1004
  if (args.country) params.set('country', args.country as string);
package/src/server.ts CHANGED
@@ -9,7 +9,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprot
9
9
  import pack from './index.js';
10
10
 
11
11
  const server = new Server(
12
- { name: '@pipeworx/mcp-newsdata', version: '0.1.4' },
12
+ { name: '@pipeworx/mcp-newsdata', version: '0.1.5' },
13
13
  { capabilities: { tools: {} } },
14
14
  );
15
15