@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 +3 -3
- package/package.json +3 -3
- package/server.json +1 -1
- package/src/index.ts +57 -2
- package/src/server.ts +1 -1
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
|
|
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
|
|
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
|
|
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.
|
|
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-
|
|
30
|
-
"sourceCommit": "
|
|
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.
|
|
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
|
|
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.
|
|
12
|
+
{ name: '@pipeworx/mcp-newsdata', version: '0.1.5' },
|
|
13
13
|
{ capabilities: { tools: {} } },
|
|
14
14
|
);
|
|
15
15
|
|