@cyanheads/gdelt-mcp-server 0.1.1
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/CLAUDE.md +405 -0
- package/Dockerfile +98 -0
- package/README.md +336 -0
- package/changelog/0.1.x/0.1.0.md +23 -0
- package/changelog/0.1.x/0.1.1.md +18 -0
- package/changelog/template.md +119 -0
- package/dist/config/server-config.d.ts +13 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +28 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/tools/date-resolution.d.ts +7 -0
- package/dist/mcp-server/tools/date-resolution.d.ts.map +1 -0
- package/dist/mcp-server/tools/date-resolution.js +13 -0
- package/dist/mcp-server/tools/date-resolution.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-coverage-breakdown.tool.d.ts +52 -0
- package/dist/mcp-server/tools/definitions/get-coverage-breakdown.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-coverage-breakdown.tool.js +182 -0
- package/dist/mcp-server/tools/definitions/get-coverage-breakdown.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-coverage-timeline.tool.d.ts +54 -0
- package/dist/mcp-server/tools/definitions/get-coverage-timeline.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-coverage-timeline.tool.js +173 -0
- package/dist/mcp-server/tools/definitions/get-coverage-timeline.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-tone-distribution.tool.d.ts +41 -0
- package/dist/mcp-server/tools/definitions/get-tone-distribution.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-tone-distribution.tool.js +143 -0
- package/dist/mcp-server/tools/definitions/get-tone-distribution.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-tv-clips.tool.d.ts +44 -0
- package/dist/mcp-server/tools/definitions/get-tv-clips.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-tv-clips.tool.js +134 -0
- package/dist/mcp-server/tools/definitions/get-tv-clips.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-tv-context.tool.d.ts +32 -0
- package/dist/mcp-server/tools/definitions/get-tv-context.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-tv-context.tool.js +114 -0
- package/dist/mcp-server/tools/definitions/get-tv-context.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-tv-trending.tool.d.ts +27 -0
- package/dist/mcp-server/tools/definitions/get-tv-trending.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-tv-trending.tool.js +82 -0
- package/dist/mcp-server/tools/definitions/get-tv-trending.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/index.d.ts +14 -0
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/index.js +14 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/list-tv-stations.tool.d.ts +32 -0
- package/dist/mcp-server/tools/definitions/list-tv-stations.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/list-tv-stations.tool.js +94 -0
- package/dist/mcp-server/tools/definitions/list-tv-stations.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/search-articles.tool.d.ts +45 -0
- package/dist/mcp-server/tools/definitions/search-articles.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/search-articles.tool.js +142 -0
- package/dist/mcp-server/tools/definitions/search-articles.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/search-tv.tool.d.ts +48 -0
- package/dist/mcp-server/tools/definitions/search-tv.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/search-tv.tool.js +159 -0
- package/dist/mcp-server/tools/definitions/search-tv.tool.js.map +1 -0
- package/dist/services/gdelt/gdelt-doc-service.d.ts +89 -0
- package/dist/services/gdelt/gdelt-doc-service.d.ts.map +1 -0
- package/dist/services/gdelt/gdelt-doc-service.js +116 -0
- package/dist/services/gdelt/gdelt-doc-service.js.map +1 -0
- package/dist/services/gdelt/gdelt-fetch.d.ts +11 -0
- package/dist/services/gdelt/gdelt-fetch.d.ts.map +1 -0
- package/dist/services/gdelt/gdelt-fetch.js +46 -0
- package/dist/services/gdelt/gdelt-fetch.js.map +1 -0
- package/dist/services/gdelt/gdelt-tv-service.d.ts +78 -0
- package/dist/services/gdelt/gdelt-tv-service.d.ts.map +1 -0
- package/dist/services/gdelt/gdelt-tv-service.js +153 -0
- package/dist/services/gdelt/gdelt-tv-service.js.map +1 -0
- package/dist/services/gdelt/rate-limiter.d.ts +19 -0
- package/dist/services/gdelt/rate-limiter.d.ts.map +1 -0
- package/dist/services/gdelt/rate-limiter.js +47 -0
- package/dist/services/gdelt/rate-limiter.js.map +1 -0
- package/dist/services/gdelt/types.d.ts +87 -0
- package/dist/services/gdelt/types.d.ts.map +1 -0
- package/dist/services/gdelt/types.js +6 -0
- package/dist/services/gdelt/types.js.map +1 -0
- package/package.json +80 -0
- package/server.json +99 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT tone distribution tool. Returns a histogram of article tone
|
|
3
|
+
* scores for articles matching a query, revealing emotional distribution of coverage.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-tone-distribution.tool
|
|
5
|
+
*/
|
|
6
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
import { getGdeltDocService } from '../../../services/gdelt/gdelt-doc-service.js';
|
|
9
|
+
export const gdeltGetToneDistribution = tool('gdelt_get_tone_distribution', {
|
|
10
|
+
title: 'Get GDELT Tone Distribution',
|
|
11
|
+
description: 'Get the tonal distribution of articles matching a query as a histogram (bins approximately -30 to +30). ' +
|
|
12
|
+
'Unlike a single average tone score, the histogram reveals whether coverage is uniformly negative, ' +
|
|
13
|
+
'bimodal (some articles extremely positive and some extremely negative), or clustered near neutral. ' +
|
|
14
|
+
'Each bin includes representative article URLs. ' +
|
|
15
|
+
'Distinct from gdelt_get_coverage_timeline (mode: tone) — this is a snapshot distribution ' +
|
|
16
|
+
'across all matching articles, not a time series. ' +
|
|
17
|
+
'Use gdelt_get_coverage_timeline with mode "tone" to see how sentiment shifted over time.',
|
|
18
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
19
|
+
errors: [
|
|
20
|
+
{
|
|
21
|
+
reason: 'no_tone_data',
|
|
22
|
+
code: JsonRpcErrorCode.NotFound,
|
|
23
|
+
when: 'No tone histogram data returned for the query.',
|
|
24
|
+
recovery: 'Broaden the query or extend the timespan to include more matching articles.',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
reason: 'gdelt_unavailable',
|
|
28
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
29
|
+
when: 'GDELT DOC API is unreachable or rate-limited.',
|
|
30
|
+
retryable: true,
|
|
31
|
+
recovery: 'Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
input: z.object({
|
|
35
|
+
query: z
|
|
36
|
+
.string()
|
|
37
|
+
.min(1)
|
|
38
|
+
.describe('Search query using GDELT syntax. Same operators as gdelt_search_articles: ' +
|
|
39
|
+
'phrases, boolean OR, sourcecountry:, sourcelang:, domain:, theme:.'),
|
|
40
|
+
timespan: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Time window relative to now, e.g. "24h", "7d", "1m". ' +
|
|
44
|
+
'Ignored when startDatetime/endDatetime are set. Maximum 3 months.'),
|
|
45
|
+
startDatetime: z
|
|
46
|
+
.string()
|
|
47
|
+
.optional()
|
|
48
|
+
.describe('Start datetime in GDELT format YYYYMMDDHHMMSS. Must pair with endDatetime.'),
|
|
49
|
+
endDatetime: z
|
|
50
|
+
.string()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe('End datetime in GDELT format YYYYMMDDHHMMSS. Must pair with startDatetime.'),
|
|
53
|
+
}),
|
|
54
|
+
output: z.object({
|
|
55
|
+
query: z.string().describe('Echoed query string.'),
|
|
56
|
+
histogram: z
|
|
57
|
+
.array(z
|
|
58
|
+
.object({
|
|
59
|
+
bin: z.number().describe('Tone bin integer (typically -30 to +30; 0 is neutral).'),
|
|
60
|
+
count: z.number().describe('Number of articles in this bin.'),
|
|
61
|
+
articles: z
|
|
62
|
+
.array(z
|
|
63
|
+
.object({
|
|
64
|
+
url: z.string().describe('Article URL.'),
|
|
65
|
+
title: z.string().describe('Article title.'),
|
|
66
|
+
})
|
|
67
|
+
.describe('A representative article for this tone bin.'))
|
|
68
|
+
.describe('Representative articles in this tone bin.'),
|
|
69
|
+
})
|
|
70
|
+
.describe('A single tone histogram bin with article count and representative articles.'))
|
|
71
|
+
.describe('Tone histogram sorted from most negative to most positive bin.'),
|
|
72
|
+
summary: z
|
|
73
|
+
.object({
|
|
74
|
+
peakNegativeBin: z
|
|
75
|
+
.number()
|
|
76
|
+
.describe('Tone bin with the highest count among negative bins (bin < 0).'),
|
|
77
|
+
peakPositiveBin: z
|
|
78
|
+
.number()
|
|
79
|
+
.describe('Tone bin with the highest count among positive bins (bin > 0).'),
|
|
80
|
+
neutralPct: z
|
|
81
|
+
.number()
|
|
82
|
+
.describe('Percentage of articles in the near-neutral range (bins -2 to +2).'),
|
|
83
|
+
})
|
|
84
|
+
.describe('Summary statistics derived from the histogram.'),
|
|
85
|
+
notice: z
|
|
86
|
+
.string()
|
|
87
|
+
.optional()
|
|
88
|
+
.describe('Recovery hint when no data was returned. Absent on successful responses.'),
|
|
89
|
+
}),
|
|
90
|
+
async handler(input, ctx) {
|
|
91
|
+
ctx.log.info('gdelt_get_tone_distribution', { query: input.query });
|
|
92
|
+
const svc = getGdeltDocService();
|
|
93
|
+
const bins = await svc.getToneDistribution({
|
|
94
|
+
query: input.query,
|
|
95
|
+
...(input.timespan && { timespan: input.timespan }),
|
|
96
|
+
...(input.startDatetime && { startDatetime: input.startDatetime }),
|
|
97
|
+
...(input.endDatetime && { endDatetime: input.endDatetime }),
|
|
98
|
+
}, ctx);
|
|
99
|
+
if (bins.length === 0) {
|
|
100
|
+
throw ctx.fail('no_tone_data', `No tone data for "${input.query}"`, {
|
|
101
|
+
recovery: {
|
|
102
|
+
hint: `No tone data for "${input.query}". Broaden the query or extend the time range.`,
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
// Compute summary
|
|
107
|
+
const negativeBins = bins.filter((b) => b.bin < 0);
|
|
108
|
+
const positiveBins = bins.filter((b) => b.bin > 0);
|
|
109
|
+
const neutralBins = bins.filter((b) => b.bin >= -2 && b.bin <= 2);
|
|
110
|
+
const totalCount = bins.reduce((sum, b) => sum + b.count, 0);
|
|
111
|
+
const neutralCount = neutralBins.reduce((sum, b) => sum + b.count, 0);
|
|
112
|
+
const peakNeg = negativeBins.reduce((max, b) => (b.count > max.count ? b : max), negativeBins[0] ?? { bin: 0, count: 0, articles: [] });
|
|
113
|
+
const peakPos = positiveBins.reduce((max, b) => (b.count > max.count ? b : max), positiveBins[0] ?? { bin: 0, count: 0, articles: [] });
|
|
114
|
+
const summary = {
|
|
115
|
+
peakNegativeBin: peakNeg.bin,
|
|
116
|
+
peakPositiveBin: peakPos.bin,
|
|
117
|
+
neutralPct: totalCount > 0 ? Math.round((neutralCount / totalCount) * 100) : 0,
|
|
118
|
+
};
|
|
119
|
+
ctx.log.info('gdelt_get_tone_distribution completed', { bins: bins.length, totalCount });
|
|
120
|
+
return { query: input.query, histogram: bins, summary };
|
|
121
|
+
},
|
|
122
|
+
format: (result) => {
|
|
123
|
+
const lines = [
|
|
124
|
+
`## GDELT Tone Distribution`,
|
|
125
|
+
`**Query:** ${result.query}`,
|
|
126
|
+
`**Peak negative bin:** ${result.summary.peakNegativeBin}`,
|
|
127
|
+
`**Peak positive bin:** ${result.summary.peakPositiveBin}`,
|
|
128
|
+
`**Neutral articles (bins -2 to +2):** ${result.summary.neutralPct}%`,
|
|
129
|
+
];
|
|
130
|
+
if (result.notice)
|
|
131
|
+
lines.push(`\n> ${result.notice}`);
|
|
132
|
+
lines.push('\n### Histogram');
|
|
133
|
+
for (const b of result.histogram) {
|
|
134
|
+
const bar = '█'.repeat(Math.min(Math.ceil(b.count / 5), 20));
|
|
135
|
+
lines.push(`**Bin ${b.bin > 0 ? '+' : ''}${b.bin}:** ${b.count} articles ${bar}`);
|
|
136
|
+
for (const a of b.articles.slice(0, 2)) {
|
|
137
|
+
lines.push(` - [${a.title}](${a.url})`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
//# sourceMappingURL=get-tone-distribution.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-tone-distribution.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-tone-distribution.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT TV clips tool. Retrieves matching TV news clips with transcript
|
|
3
|
+
* excerpts and Internet Archive viewing links.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-tv-clips.tool
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
export declare const gdeltGetTvClips: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
9
|
+
query: z.ZodString;
|
|
10
|
+
stations: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
11
|
+
timespan: z.ZodOptional<z.ZodString>;
|
|
12
|
+
startDatetime: z.ZodOptional<z.ZodString>;
|
|
13
|
+
endDatetime: z.ZodOptional<z.ZodString>;
|
|
14
|
+
maxRecords: z.ZodDefault<z.ZodNumber>;
|
|
15
|
+
sort: z.ZodDefault<z.ZodEnum<{
|
|
16
|
+
relevance: "relevance";
|
|
17
|
+
dateDesc: "dateDesc";
|
|
18
|
+
dateAsc: "dateAsc";
|
|
19
|
+
}>>;
|
|
20
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
21
|
+
query: z.ZodString;
|
|
22
|
+
clips: z.ZodArray<z.ZodObject<{
|
|
23
|
+
show: z.ZodString;
|
|
24
|
+
station: z.ZodString;
|
|
25
|
+
date: z.ZodString;
|
|
26
|
+
snippet: z.ZodString;
|
|
27
|
+
archiveUrl: z.ZodString;
|
|
28
|
+
thumbnail: z.ZodOptional<z.ZodString>;
|
|
29
|
+
}, z.core.$strip>>;
|
|
30
|
+
totalReturned: z.ZodNumber;
|
|
31
|
+
notice: z.ZodOptional<z.ZodString>;
|
|
32
|
+
}, z.core.$strip>, readonly [{
|
|
33
|
+
readonly reason: "no_clips";
|
|
34
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
35
|
+
readonly when: "No TV clips matched the query in the specified time range.";
|
|
36
|
+
readonly recovery: string;
|
|
37
|
+
}, {
|
|
38
|
+
readonly reason: "gdelt_unavailable";
|
|
39
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
40
|
+
readonly when: "GDELT TV API is unreachable or rate-limited.";
|
|
41
|
+
readonly retryable: true;
|
|
42
|
+
readonly recovery: "Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.";
|
|
43
|
+
}]>;
|
|
44
|
+
//# sourceMappingURL=get-tv-clips.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-tv-clips.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-tv-clips.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkJ1B,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT TV clips tool. Retrieves matching TV news clips with transcript
|
|
3
|
+
* excerpts and Internet Archive viewing links.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-tv-clips.tool
|
|
5
|
+
*/
|
|
6
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
import { getGdeltTvService } from '../../../services/gdelt/gdelt-tv-service.js';
|
|
9
|
+
export const gdeltGetTvClips = tool('gdelt_get_tv_clips', {
|
|
10
|
+
title: 'Get GDELT TV Clips',
|
|
11
|
+
description: "Retrieve the top matching TV news clips (up to 3,000) for a query from the Internet Archive's " +
|
|
12
|
+
'Television News Archive. Each clip includes show name, station, air timestamp, a 15-second ' +
|
|
13
|
+
'transcript excerpt, and a direct link to view the full one-minute clip. ' +
|
|
14
|
+
'Use after gdelt_search_tv to read the actual transcript content driving a coverage spike. ' +
|
|
15
|
+
'Archive coverage spans 2009–October 2024.',
|
|
16
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
17
|
+
errors: [
|
|
18
|
+
{
|
|
19
|
+
reason: 'no_clips',
|
|
20
|
+
code: JsonRpcErrorCode.NotFound,
|
|
21
|
+
when: 'No TV clips matched the query in the specified time range.',
|
|
22
|
+
recovery: 'TV data ends October 2024 — supply explicit startDatetime/endDatetime within 2009–2024, ' +
|
|
23
|
+
'or verify station IDs with gdelt_list_tv_stations.',
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
reason: 'gdelt_unavailable',
|
|
27
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
28
|
+
when: 'GDELT TV API is unreachable or rate-limited.',
|
|
29
|
+
retryable: true,
|
|
30
|
+
recovery: 'Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
input: z.object({
|
|
34
|
+
query: z
|
|
35
|
+
.string()
|
|
36
|
+
.min(1)
|
|
37
|
+
.describe('Search query for TV transcript content. Same TV operators as gdelt_search_tv: ' +
|
|
38
|
+
'station:CNN, network:CBS, market:"National", show:"Anderson Cooper", context:"vaccine".'),
|
|
39
|
+
stations: z
|
|
40
|
+
.array(z.string())
|
|
41
|
+
.optional()
|
|
42
|
+
.describe('Station IDs to filter to (e.g. ["CNN", "FOXNEWS"]). ' +
|
|
43
|
+
'Omit for all stations. Use gdelt_list_tv_stations to see valid IDs.'),
|
|
44
|
+
timespan: z
|
|
45
|
+
.string()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe('Time window, e.g. "1m", "6m". Ignored when startDatetime/endDatetime are set. ' +
|
|
48
|
+
'TV data spans 2009–October 2024.'),
|
|
49
|
+
startDatetime: z
|
|
50
|
+
.string()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe('Start datetime in GDELT format YYYYMMDDHHMMSS. Must pair with endDatetime.'),
|
|
53
|
+
endDatetime: z
|
|
54
|
+
.string()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe('End datetime in GDELT format YYYYMMDDHHMMSS. Must pair with startDatetime.'),
|
|
57
|
+
maxRecords: z
|
|
58
|
+
.number()
|
|
59
|
+
.int()
|
|
60
|
+
.min(1)
|
|
61
|
+
.max(3000)
|
|
62
|
+
.default(50)
|
|
63
|
+
.describe('Maximum number of clips to return (1–3000).'),
|
|
64
|
+
sort: z
|
|
65
|
+
.enum(['relevance', 'dateDesc', 'dateAsc'])
|
|
66
|
+
.default('relevance')
|
|
67
|
+
.describe('Sort order: relevance (default), dateDesc (newest first), dateAsc (oldest first).'),
|
|
68
|
+
}),
|
|
69
|
+
output: z.object({
|
|
70
|
+
query: z.string().describe('Echoed query string.'),
|
|
71
|
+
clips: z
|
|
72
|
+
.array(z
|
|
73
|
+
.object({
|
|
74
|
+
show: z.string().describe('Show name (e.g. "Anderson Cooper 360").'),
|
|
75
|
+
station: z.string().describe('Station ID (e.g. "CNN").'),
|
|
76
|
+
date: z.string().describe('Air datetime in ISO 8601 format.'),
|
|
77
|
+
snippet: z.string().describe('15-second transcript excerpt surrounding the match.'),
|
|
78
|
+
archiveUrl: z.string().describe('Internet Archive URL to view the full 1-minute clip.'),
|
|
79
|
+
thumbnail: z
|
|
80
|
+
.string()
|
|
81
|
+
.optional()
|
|
82
|
+
.describe('Clip thumbnail URL when provided by the archive.'),
|
|
83
|
+
})
|
|
84
|
+
.describe('A single TV news clip with transcript excerpt and archive link.'))
|
|
85
|
+
.describe('Matching TV clips sorted per the sort parameter.'),
|
|
86
|
+
totalReturned: z.number().describe('Number of clips returned.'),
|
|
87
|
+
notice: z
|
|
88
|
+
.string()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('Recovery hint when no clips matched. Absent on successful responses.'),
|
|
91
|
+
}),
|
|
92
|
+
async handler(input, ctx) {
|
|
93
|
+
ctx.log.info('gdelt_get_tv_clips', { query: input.query, maxRecords: input.maxRecords });
|
|
94
|
+
const svc = getGdeltTvService();
|
|
95
|
+
const clips = await svc.getTvClips({
|
|
96
|
+
query: input.query,
|
|
97
|
+
...(input.stations?.length && { stations: input.stations }),
|
|
98
|
+
...(input.timespan && { timespan: input.timespan }),
|
|
99
|
+
...(input.startDatetime && { startDatetime: input.startDatetime }),
|
|
100
|
+
...(input.endDatetime && { endDatetime: input.endDatetime }),
|
|
101
|
+
maxRecords: input.maxRecords,
|
|
102
|
+
sort: input.sort,
|
|
103
|
+
}, ctx);
|
|
104
|
+
if (clips.length === 0) {
|
|
105
|
+
throw ctx.fail('no_clips', `No TV clips matched "${input.query}"`, {
|
|
106
|
+
recovery: {
|
|
107
|
+
hint: `No TV clips for "${input.query}". TV data ends October 2024 — ` +
|
|
108
|
+
`supply explicit startDatetime/endDatetime within 2009–2024, or verify station IDs with gdelt_list_tv_stations.`,
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
ctx.log.info('gdelt_get_tv_clips completed', { count: clips.length });
|
|
113
|
+
return { query: input.query, clips, totalReturned: clips.length };
|
|
114
|
+
},
|
|
115
|
+
format: (result) => {
|
|
116
|
+
const lines = [
|
|
117
|
+
`## GDELT TV Clips`,
|
|
118
|
+
`**Query:** ${result.query}`,
|
|
119
|
+
`**Clips returned:** ${result.totalReturned}`,
|
|
120
|
+
];
|
|
121
|
+
if (result.notice)
|
|
122
|
+
lines.push(`\n> ${result.notice}`);
|
|
123
|
+
for (const c of result.clips) {
|
|
124
|
+
lines.push(`\n### ${c.show} — ${c.station}`);
|
|
125
|
+
lines.push(`**Date:** ${c.date}`);
|
|
126
|
+
lines.push(`**Snippet:** ${c.snippet}`);
|
|
127
|
+
lines.push(`**View clip:** ${c.archiveUrl}`);
|
|
128
|
+
if (c.thumbnail)
|
|
129
|
+
lines.push(`**Thumbnail:** ${c.thumbnail}`);
|
|
130
|
+
}
|
|
131
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=get-tv-clips.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-tv-clips.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-tv-clips.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAEzE,MAAM,CAAC,MAAM,eAAe,GAAG,IAAI,CAAC,oBAAoB,EAAE;IACxD,KAAK,EAAE,oBAAoB;IAC3B,WAAW,EACT,gGAAgG;QAChG,6FAA6F;QAC7F,0EAA0E;QAC1E,4FAA4F;QAC5F,2CAA2C;IAC7C,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;IAExD,MAAM,EAAE;QACN;YACE,MAAM,EAAE,UAAU;YAClB,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,4DAA4D;YAClE,QAAQ,EACN,0FAA0F;gBAC1F,oDAAoD;SACvD;QACD;YACE,MAAM,EAAE,mBAAmB;YAC3B,IAAI,EAAE,gBAAgB,CAAC,kBAAkB;YACzC,IAAI,EAAE,8CAA8C;YACpD,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,mFAAmF;SAC9F;KACF;IAED,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CACP,gFAAgF;YAC9E,yFAAyF,CAC5F;QACH,QAAQ,EAAE,CAAC;aACR,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;aACjB,QAAQ,EAAE;aACV,QAAQ,CACP,sDAAsD;YACpD,qEAAqE,CACxE;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,gFAAgF;YAC9E,kCAAkC,CACrC;QACH,aAAa,EAAE,CAAC;aACb,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,4EAA4E,CAAC;QACzF,WAAW,EAAE,CAAC;aACX,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,4EAA4E,CAAC;QACzF,UAAU,EAAE,CAAC;aACV,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,IAAI,CAAC;aACT,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,6CAA6C,CAAC;QAC1D,IAAI,EAAE,CAAC;aACJ,IAAI,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;aAC1C,OAAO,CAAC,WAAW,CAAC;aACpB,QAAQ,CACP,mFAAmF,CACpF;KACJ,CAAC;IAEF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAClD,KAAK,EAAE,CAAC;aACL,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YACpE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC;YACxD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;YAC7D,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,qDAAqD,CAAC;YACnF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;YACvF,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,kDAAkD,CAAC;SAChE,CAAC;aACD,QAAQ,CAAC,iEAAiE,CAAC,CAC/E;aACA,QAAQ,CAAC,kDAAkD,CAAC;QAC/D,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QAC/D,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,sEAAsE,CAAC;KACpF,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;QACzF,MAAM,GAAG,GAAG,iBAAiB,EAAE,CAAC;QAEhC,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,UAAU,CAChC;YACE,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC3D,GAAG,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;YACnD,GAAG,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,aAAa,EAAE,KAAK,CAAC,aAAa,EAAE,CAAC;YAClE,GAAG,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;YAC5D,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,EACD,GAAG,CACJ,CAAC;QAEF,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,wBAAwB,KAAK,CAAC,KAAK,GAAG,EAAE;gBACjE,QAAQ,EAAE;oBACR,IAAI,EACF,oBAAoB,KAAK,CAAC,KAAK,iCAAiC;wBAChE,gHAAgH;iBACnH;aACF,CAAC,CAAC;QACL,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QACtE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;IACpE,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,KAAK,GAAa;YACtB,mBAAmB;YACnB,cAAc,MAAM,CAAC,KAAK,EAAE;YAC5B,uBAAuB,MAAM,CAAC,aAAa,EAAE;SAC9C,CAAC;QACF,IAAI,MAAM,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;QACtD,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7C,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;YAClC,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;YACxC,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;YAC7C,IAAI,CAAC,CAAC,SAAS;gBAAE,KAAK,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT TV context tool. Returns co-occurring words and phrases from
|
|
3
|
+
* TV news clips matching a query — the vocabulary framing a topic on television.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-tv-context.tool
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
export declare const gdeltGetTvContext: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
9
|
+
query: z.ZodString;
|
|
10
|
+
stations: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
11
|
+
timespan: z.ZodOptional<z.ZodString>;
|
|
12
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
13
|
+
query: z.ZodString;
|
|
14
|
+
words: z.ZodArray<z.ZodObject<{
|
|
15
|
+
label: z.ZodString;
|
|
16
|
+
score: z.ZodNumber;
|
|
17
|
+
}, z.core.$strip>>;
|
|
18
|
+
clipsAnalyzed: z.ZodNumber;
|
|
19
|
+
notice: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>, readonly [{
|
|
21
|
+
readonly reason: "no_context";
|
|
22
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
23
|
+
readonly when: "No context words found — no clips matched the query.";
|
|
24
|
+
readonly recovery: "Broaden the query, extend the timespan, or verify station IDs with gdelt_list_tv_stations.";
|
|
25
|
+
}, {
|
|
26
|
+
readonly reason: "gdelt_unavailable";
|
|
27
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
28
|
+
readonly when: "GDELT TV API is unreachable or rate-limited.";
|
|
29
|
+
readonly retryable: true;
|
|
30
|
+
readonly recovery: "Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.";
|
|
31
|
+
}]>;
|
|
32
|
+
//# sourceMappingURL=get-tv-context.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-tv-context.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-tv-context.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;GA6H5B,CAAC"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT TV context tool. Returns co-occurring words and phrases from
|
|
3
|
+
* TV news clips matching a query — the vocabulary framing a topic on television.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-tv-context.tool
|
|
5
|
+
*/
|
|
6
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
import { getGdeltTvService } from '../../../services/gdelt/gdelt-tv-service.js';
|
|
9
|
+
export const gdeltGetTvContext = tool('gdelt_get_tv_context', {
|
|
10
|
+
title: 'Get GDELT TV Context',
|
|
11
|
+
description: 'Get the top co-occurring words and phrases from TV news clips matching a query — ' +
|
|
12
|
+
'the vocabulary framing a topic on television. ' +
|
|
13
|
+
'Returns the most frequent non-stopword terms from matching clips, with relative frequency scores ' +
|
|
14
|
+
'(0–100, where 100 = the query term itself). ' +
|
|
15
|
+
'Use to understand narrative framing, identify related concepts mentioned alongside a topic, ' +
|
|
16
|
+
'or generate follow-up search terms. ' +
|
|
17
|
+
'TV data spans 2009–October 2024.',
|
|
18
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
19
|
+
errors: [
|
|
20
|
+
{
|
|
21
|
+
reason: 'no_context',
|
|
22
|
+
code: JsonRpcErrorCode.NotFound,
|
|
23
|
+
when: 'No context words found — no clips matched the query.',
|
|
24
|
+
recovery: 'Broaden the query, extend the timespan, or verify station IDs with gdelt_list_tv_stations.',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
reason: 'gdelt_unavailable',
|
|
28
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
29
|
+
when: 'GDELT TV API is unreachable or rate-limited.',
|
|
30
|
+
retryable: true,
|
|
31
|
+
recovery: 'Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
input: z.object({
|
|
35
|
+
query: z
|
|
36
|
+
.string()
|
|
37
|
+
.min(1)
|
|
38
|
+
.describe('Search query for TV transcript content. Same TV operators as gdelt_search_tv: ' +
|
|
39
|
+
'station:CNN, network:CBS, market:"National", show:"Anderson Cooper", context:"vaccine".'),
|
|
40
|
+
stations: z
|
|
41
|
+
.array(z.string())
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Station IDs to filter to. Omit for all stations. ' +
|
|
44
|
+
'Use gdelt_list_tv_stations to see valid IDs.'),
|
|
45
|
+
timespan: z
|
|
46
|
+
.string()
|
|
47
|
+
.optional()
|
|
48
|
+
.describe('Time window, e.g. "1m", "6m". TV data spans 2009–October 2024.'),
|
|
49
|
+
}),
|
|
50
|
+
output: z.object({
|
|
51
|
+
query: z.string().describe('Echoed query string.'),
|
|
52
|
+
words: z
|
|
53
|
+
.array(z
|
|
54
|
+
.object({
|
|
55
|
+
label: z.string().describe('Co-occurring word or phrase.'),
|
|
56
|
+
score: z
|
|
57
|
+
.number()
|
|
58
|
+
.describe('Relative frequency score (0–100). The query term itself scores 100; ' +
|
|
59
|
+
'other terms are proportional to their co-occurrence frequency.'),
|
|
60
|
+
})
|
|
61
|
+
.describe('A co-occurring term with its relative frequency score.'))
|
|
62
|
+
.describe('Co-occurring terms sorted by score descending.'),
|
|
63
|
+
clipsAnalyzed: z
|
|
64
|
+
.number()
|
|
65
|
+
.describe('Number of matching clips from which co-occurrences were computed.'),
|
|
66
|
+
notice: z
|
|
67
|
+
.string()
|
|
68
|
+
.optional()
|
|
69
|
+
.describe('Recovery hint when no context was found. Absent on successful responses.'),
|
|
70
|
+
}),
|
|
71
|
+
async handler(input, ctx) {
|
|
72
|
+
ctx.log.info('gdelt_get_tv_context', { query: input.query });
|
|
73
|
+
const svc = getGdeltTvService();
|
|
74
|
+
const result = await svc.getTvContext({
|
|
75
|
+
query: input.query,
|
|
76
|
+
...(input.stations?.length && { stations: input.stations }),
|
|
77
|
+
...(input.timespan && { timespan: input.timespan }),
|
|
78
|
+
}, ctx);
|
|
79
|
+
if (result.words.length === 0) {
|
|
80
|
+
throw ctx.fail('no_context', `No context words for "${input.query}"`, {
|
|
81
|
+
recovery: {
|
|
82
|
+
hint: `No TV context data for "${input.query}". TV data ends October 2024 — ` +
|
|
83
|
+
`broaden the query or use gdelt_list_tv_stations to check coverage.`,
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
ctx.log.info('gdelt_get_tv_context completed', { wordCount: result.words.length });
|
|
88
|
+
return {
|
|
89
|
+
query: input.query,
|
|
90
|
+
words: result.words.sort((a, b) => b.score - a.score),
|
|
91
|
+
clipsAnalyzed: result.clipsAnalyzed,
|
|
92
|
+
};
|
|
93
|
+
},
|
|
94
|
+
format: (result) => {
|
|
95
|
+
const lines = [
|
|
96
|
+
`## GDELT TV Context`,
|
|
97
|
+
`**Query:** ${result.query}`,
|
|
98
|
+
`**Clips analyzed:** ${result.clipsAnalyzed}`,
|
|
99
|
+
`**Co-occurring terms:** ${result.words.length}`,
|
|
100
|
+
];
|
|
101
|
+
if (result.notice)
|
|
102
|
+
lines.push(`\n> ${result.notice}`);
|
|
103
|
+
lines.push('\n### Top Terms');
|
|
104
|
+
for (const w of result.words.slice(0, 50)) {
|
|
105
|
+
const bar = '█'.repeat(Math.round(w.score / 5));
|
|
106
|
+
lines.push(`- **${w.label}**: ${w.score.toFixed(1)} ${bar}`);
|
|
107
|
+
}
|
|
108
|
+
if (result.words.length > 50) {
|
|
109
|
+
lines.push(`\n_… ${result.words.length - 50} more terms_`);
|
|
110
|
+
}
|
|
111
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
112
|
+
},
|
|
113
|
+
});
|
|
114
|
+
//# sourceMappingURL=get-tv-context.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-tv-context.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-tv-context.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT TV trending tool. Returns trending topics currently dominating
|
|
3
|
+
* US television news — no query required.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-tv-trending.tool
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
export declare const gdeltGetTvTrending: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{}, z.core.$strip>, z.ZodObject<{
|
|
9
|
+
topics: z.ZodArray<z.ZodObject<{
|
|
10
|
+
label: z.ZodString;
|
|
11
|
+
score: z.ZodNumber;
|
|
12
|
+
}, z.core.$strip>>;
|
|
13
|
+
totalCount: z.ZodNumber;
|
|
14
|
+
notice: z.ZodOptional<z.ZodString>;
|
|
15
|
+
}, z.core.$strip>, readonly [{
|
|
16
|
+
readonly reason: "no_trending";
|
|
17
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
18
|
+
readonly when: "No trending topics returned — the endpoint returned an empty list.";
|
|
19
|
+
readonly recovery: "The TV trending endpoint reflects the October 2024 archive cutoff. Retry after a short delay.";
|
|
20
|
+
}, {
|
|
21
|
+
readonly reason: "gdelt_unavailable";
|
|
22
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
23
|
+
readonly when: "GDELT TV API is unreachable or rate-limited.";
|
|
24
|
+
readonly retryable: true;
|
|
25
|
+
readonly recovery: "Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.";
|
|
26
|
+
}]>;
|
|
27
|
+
//# sourceMappingURL=get-tv-trending.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-tv-trending.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-tv-trending.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAGjE,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;GAoF7B,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT TV trending tool. Returns trending topics currently dominating
|
|
3
|
+
* US television news — no query required.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-tv-trending.tool
|
|
5
|
+
*/
|
|
6
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
import { getGdeltTvService } from '../../../services/gdelt/gdelt-tv-service.js';
|
|
9
|
+
export const gdeltGetTvTrending = tool('gdelt_get_tv_trending', {
|
|
10
|
+
title: 'Get GDELT TV Trending',
|
|
11
|
+
description: 'Retrieve trending topics, keywords, and phrases currently dominating US television news ' +
|
|
12
|
+
'across national networks. No query required — returns the top memes of the present news cycle. ' +
|
|
13
|
+
'Updated every 15 minutes. ' +
|
|
14
|
+
'Note: the GDELT TV archive feed stopped updating around October 2024; results from this endpoint ' +
|
|
15
|
+
'reflect that most-recent archived data rather than a live feed.',
|
|
16
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
17
|
+
errors: [
|
|
18
|
+
{
|
|
19
|
+
reason: 'no_trending',
|
|
20
|
+
code: JsonRpcErrorCode.NotFound,
|
|
21
|
+
when: 'No trending topics returned — the endpoint returned an empty list.',
|
|
22
|
+
recovery: 'The TV trending endpoint reflects the October 2024 archive cutoff. Retry after a short delay.',
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
reason: 'gdelt_unavailable',
|
|
26
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
27
|
+
when: 'GDELT TV API is unreachable or rate-limited.',
|
|
28
|
+
retryable: true,
|
|
29
|
+
recovery: 'Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
input: z.object({}),
|
|
33
|
+
output: z.object({
|
|
34
|
+
topics: z
|
|
35
|
+
.array(z
|
|
36
|
+
.object({
|
|
37
|
+
label: z.string().describe('Trending topic, keyword, or phrase.'),
|
|
38
|
+
score: z
|
|
39
|
+
.number()
|
|
40
|
+
.describe('Relative trending score. Higher scores indicate topics with greater current airtime.'),
|
|
41
|
+
})
|
|
42
|
+
.describe('A single trending topic with its relative score.'))
|
|
43
|
+
.describe('Trending topics sorted by score descending.'),
|
|
44
|
+
totalCount: z.number().describe('Number of trending topics returned.'),
|
|
45
|
+
notice: z
|
|
46
|
+
.string()
|
|
47
|
+
.optional()
|
|
48
|
+
.describe('Recovery hint when no topics were returned. Absent on successful responses.'),
|
|
49
|
+
}),
|
|
50
|
+
async handler(_input, ctx) {
|
|
51
|
+
ctx.log.info('gdelt_get_tv_trending');
|
|
52
|
+
const svc = getGdeltTvService();
|
|
53
|
+
const topics = await svc.getTvTrending(ctx);
|
|
54
|
+
if (topics.length === 0) {
|
|
55
|
+
throw ctx.fail('no_trending', 'No trending topics returned', {
|
|
56
|
+
...ctx.recoveryFor('no_trending'),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
ctx.log.info('gdelt_get_tv_trending completed', { count: topics.length });
|
|
60
|
+
return {
|
|
61
|
+
topics: topics.sort((a, b) => b.score - a.score),
|
|
62
|
+
totalCount: topics.length,
|
|
63
|
+
};
|
|
64
|
+
},
|
|
65
|
+
format: (result) => {
|
|
66
|
+
const lines = [
|
|
67
|
+
`## GDELT TV Trending Topics`,
|
|
68
|
+
`**Total topics:** ${result.totalCount}`,
|
|
69
|
+
`_Note: reflects the October 2024 TV archive cutoff, not a live feed_`,
|
|
70
|
+
];
|
|
71
|
+
if (result.notice)
|
|
72
|
+
lines.push(`\n> ${result.notice}`);
|
|
73
|
+
lines.push('\n### Trending Now');
|
|
74
|
+
for (const t of result.topics.slice(0, 50)) {
|
|
75
|
+
lines.push(`- **${t.label}** (score: ${t.score.toFixed(2)})`);
|
|
76
|
+
}
|
|
77
|
+
if (result.totalCount > 50)
|
|
78
|
+
lines.push(`\n_… ${result.totalCount - 50} more topics_`);
|
|
79
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
//# sourceMappingURL=get-tv-trending.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-tv-trending.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-tv-trending.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Barrel export for all GDELT MCP tool definitions.
|
|
3
|
+
* @module mcp-server/tools/definitions/index
|
|
4
|
+
*/
|
|
5
|
+
export { gdeltGetCoverageBreakdown } from './get-coverage-breakdown.tool.js';
|
|
6
|
+
export { gdeltGetCoverageTimeline } from './get-coverage-timeline.tool.js';
|
|
7
|
+
export { gdeltGetToneDistribution } from './get-tone-distribution.tool.js';
|
|
8
|
+
export { gdeltGetTvClips } from './get-tv-clips.tool.js';
|
|
9
|
+
export { gdeltGetTvContext } from './get-tv-context.tool.js';
|
|
10
|
+
export { gdeltGetTvTrending } from './get-tv-trending.tool.js';
|
|
11
|
+
export { gdeltListTvStations } from './list-tv-stations.tool.js';
|
|
12
|
+
export { gdeltSearchArticles } from './search-articles.tool.js';
|
|
13
|
+
export { gdeltSearchTv } from './search-tv.tool.js';
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|