@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,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT coverage breakdown tool. Breaks down coverage volume by source
|
|
3
|
+
* language or source country over time using the GDELT DOC API.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-coverage-breakdown.tool
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
export declare const gdeltGetCoverageBreakdown: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
9
|
+
query: z.ZodString;
|
|
10
|
+
breakdownBy: z.ZodEnum<{
|
|
11
|
+
language: "language";
|
|
12
|
+
country: "country";
|
|
13
|
+
}>;
|
|
14
|
+
timespan: z.ZodOptional<z.ZodString>;
|
|
15
|
+
startDatetime: z.ZodOptional<z.ZodString>;
|
|
16
|
+
endDatetime: z.ZodOptional<z.ZodString>;
|
|
17
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
18
|
+
query: z.ZodString;
|
|
19
|
+
breakdownBy: z.ZodEnum<{
|
|
20
|
+
language: "language";
|
|
21
|
+
country: "country";
|
|
22
|
+
}>;
|
|
23
|
+
dateResolution: z.ZodEnum<{
|
|
24
|
+
hour: "hour";
|
|
25
|
+
day: "day";
|
|
26
|
+
}>;
|
|
27
|
+
topSeries: z.ZodArray<z.ZodObject<{
|
|
28
|
+
label: z.ZodString;
|
|
29
|
+
data: z.ZodArray<z.ZodObject<{
|
|
30
|
+
date: z.ZodString;
|
|
31
|
+
value: z.ZodNumber;
|
|
32
|
+
}, z.core.$strip>>;
|
|
33
|
+
}, z.core.$strip>>;
|
|
34
|
+
otherAggregated: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
35
|
+
date: z.ZodString;
|
|
36
|
+
value: z.ZodNumber;
|
|
37
|
+
}, z.core.$strip>>>;
|
|
38
|
+
seriesCount: z.ZodNumber;
|
|
39
|
+
notice: z.ZodOptional<z.ZodString>;
|
|
40
|
+
}, z.core.$strip>, readonly [{
|
|
41
|
+
readonly reason: "no_breakdown_data";
|
|
42
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
43
|
+
readonly when: "No breakdown data returned for the query.";
|
|
44
|
+
readonly recovery: "Broaden the query, extend the timespan, or verify the query operators are correct.";
|
|
45
|
+
}, {
|
|
46
|
+
readonly reason: "gdelt_unavailable";
|
|
47
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
48
|
+
readonly when: "GDELT DOC API is unreachable or rate-limited.";
|
|
49
|
+
readonly retryable: true;
|
|
50
|
+
readonly recovery: "Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.";
|
|
51
|
+
}]>;
|
|
52
|
+
//# sourceMappingURL=get-coverage-breakdown.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-coverage-breakdown.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-coverage-breakdown.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAOjE,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+MpC,CAAC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT coverage breakdown tool. Breaks down coverage volume by source
|
|
3
|
+
* language or source country over time using the GDELT DOC API.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-coverage-breakdown.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
|
+
import { inferDateResolution } from '../date-resolution.js';
|
|
10
|
+
/** Maximum number of series to include before aggregating the rest into "Other". */
|
|
11
|
+
const MAX_SERIES = 10;
|
|
12
|
+
export const gdeltGetCoverageBreakdown = tool('gdelt_get_coverage_breakdown', {
|
|
13
|
+
title: 'Get GDELT Coverage Breakdown',
|
|
14
|
+
description: 'Break down news coverage volume over time by source language or source country, returning a ' +
|
|
15
|
+
'multi-series time series (one series per language or country). ' +
|
|
16
|
+
'Shows which countries or languages drove early vs. late coverage — useful for tracing how a ' +
|
|
17
|
+
'story propagated geographically or across language communities. ' +
|
|
18
|
+
'Returns up to 10 series by total volume; remaining series are aggregated into an "Other" bucket. ' +
|
|
19
|
+
'Use breakdownBy "country" with the signal-detection chain to map geographic attention, ' +
|
|
20
|
+
'or "language" to detect non-English media surges.',
|
|
21
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
22
|
+
errors: [
|
|
23
|
+
{
|
|
24
|
+
reason: 'no_breakdown_data',
|
|
25
|
+
code: JsonRpcErrorCode.NotFound,
|
|
26
|
+
when: 'No breakdown data returned for the query.',
|
|
27
|
+
recovery: 'Broaden the query, extend the timespan, or verify the query operators are correct.',
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
reason: 'gdelt_unavailable',
|
|
31
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
32
|
+
when: 'GDELT DOC API is unreachable or rate-limited.',
|
|
33
|
+
retryable: true,
|
|
34
|
+
recovery: 'Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
input: z.object({
|
|
38
|
+
query: z
|
|
39
|
+
.string()
|
|
40
|
+
.min(1)
|
|
41
|
+
.describe('Search query using GDELT syntax. Same operators as gdelt_search_articles: ' +
|
|
42
|
+
'phrases, boolean OR, sourcecountry:, sourcelang:, domain:, theme:.'),
|
|
43
|
+
breakdownBy: z
|
|
44
|
+
.enum(['language', 'country'])
|
|
45
|
+
.describe('Breakdown dimension: "language" for source language time series, ' +
|
|
46
|
+
'"country" for source country time series.'),
|
|
47
|
+
timespan: z
|
|
48
|
+
.string()
|
|
49
|
+
.optional()
|
|
50
|
+
.describe('Time window relative to now, e.g. "24h", "7d", "1m". ' +
|
|
51
|
+
'Ignored when startDatetime/endDatetime are set. Maximum 3 months.'),
|
|
52
|
+
startDatetime: z
|
|
53
|
+
.string()
|
|
54
|
+
.optional()
|
|
55
|
+
.describe('Start datetime in GDELT format YYYYMMDDHHMMSS. Must pair with endDatetime.'),
|
|
56
|
+
endDatetime: z
|
|
57
|
+
.string()
|
|
58
|
+
.optional()
|
|
59
|
+
.describe('End datetime in GDELT format YYYYMMDDHHMMSS. Must pair with startDatetime.'),
|
|
60
|
+
}),
|
|
61
|
+
output: z.object({
|
|
62
|
+
query: z.string().describe('Echoed query string.'),
|
|
63
|
+
breakdownBy: z.enum(['language', 'country']).describe('Breakdown dimension used.'),
|
|
64
|
+
dateResolution: z.enum(['hour', 'day']).describe('Temporal resolution of data points.'),
|
|
65
|
+
topSeries: z
|
|
66
|
+
.array(z
|
|
67
|
+
.object({
|
|
68
|
+
label: z.string().describe('Series label (language name or country name).'),
|
|
69
|
+
data: z
|
|
70
|
+
.array(z
|
|
71
|
+
.object({
|
|
72
|
+
date: z.string().describe('Timestep in ISO 8601 format.'),
|
|
73
|
+
value: z.number().describe('Normalized coverage volume at this timestep.'),
|
|
74
|
+
})
|
|
75
|
+
.describe('A single data point for this series.'))
|
|
76
|
+
.describe('Time-ordered data points for this series.'),
|
|
77
|
+
})
|
|
78
|
+
.describe('A single language or country coverage series.'))
|
|
79
|
+
.describe('Top 10 series by total coverage volume.'),
|
|
80
|
+
otherAggregated: z
|
|
81
|
+
.array(z
|
|
82
|
+
.object({
|
|
83
|
+
date: z.string().describe('Timestep in ISO 8601 format.'),
|
|
84
|
+
value: z.number().describe('Aggregated coverage volume for all remaining series.'),
|
|
85
|
+
})
|
|
86
|
+
.describe('A single aggregated data point for the "Other" bucket.'))
|
|
87
|
+
.optional()
|
|
88
|
+
.describe('Combined time series for all series beyond the top 10. Omitted when all series fit.'),
|
|
89
|
+
seriesCount: z.number().describe('Total number of series before truncation to top 10.'),
|
|
90
|
+
notice: z
|
|
91
|
+
.string()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe('Recovery hint when no data was returned. Absent on successful responses.'),
|
|
94
|
+
}),
|
|
95
|
+
async handler(input, ctx) {
|
|
96
|
+
ctx.log.info('gdelt_get_coverage_breakdown', {
|
|
97
|
+
query: input.query,
|
|
98
|
+
breakdownBy: input.breakdownBy,
|
|
99
|
+
});
|
|
100
|
+
const svc = getGdeltDocService();
|
|
101
|
+
const modeMap = {
|
|
102
|
+
language: 'timelinelang',
|
|
103
|
+
country: 'timelinesourcecountry',
|
|
104
|
+
};
|
|
105
|
+
const allSeries = await svc.getBreakdown({
|
|
106
|
+
query: input.query,
|
|
107
|
+
mode: modeMap[input.breakdownBy],
|
|
108
|
+
...(input.timespan && { timespan: input.timespan }),
|
|
109
|
+
...(input.startDatetime && { startDatetime: input.startDatetime }),
|
|
110
|
+
...(input.endDatetime && { endDatetime: input.endDatetime }),
|
|
111
|
+
}, ctx);
|
|
112
|
+
if (allSeries.length === 0) {
|
|
113
|
+
throw ctx.fail('no_breakdown_data', `No breakdown data for "${input.query}"`, {
|
|
114
|
+
recovery: {
|
|
115
|
+
hint: `No breakdown data for "${input.query}". Try broadening the query or extending the time range.`,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
// Sort by total volume descending, take top MAX_SERIES
|
|
120
|
+
const sorted = allSeries
|
|
121
|
+
.map((s) => ({
|
|
122
|
+
...s,
|
|
123
|
+
total: s.data.reduce((sum, d) => sum + d.value, 0),
|
|
124
|
+
}))
|
|
125
|
+
.sort((a, b) => b.total - a.total);
|
|
126
|
+
const topSeries = sorted.slice(0, MAX_SERIES).map(({ total: _, ...s }) => s);
|
|
127
|
+
const remainingSeries = sorted.slice(MAX_SERIES);
|
|
128
|
+
let otherAggregated;
|
|
129
|
+
if (remainingSeries.length > 0) {
|
|
130
|
+
const dateMap = new Map();
|
|
131
|
+
for (const s of remainingSeries) {
|
|
132
|
+
for (const d of s.data) {
|
|
133
|
+
dateMap.set(d.date, (dateMap.get(d.date) ?? 0) + d.value);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
otherAggregated = Array.from(dateMap.entries())
|
|
137
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
138
|
+
.map(([date, value]) => ({ date, value }));
|
|
139
|
+
}
|
|
140
|
+
const allDates = topSeries.flatMap((s) => s.data.map((d) => d.date));
|
|
141
|
+
const dateResolution = inferDateResolution(allDates);
|
|
142
|
+
ctx.log.info('gdelt_get_coverage_breakdown completed', {
|
|
143
|
+
totalSeries: allSeries.length,
|
|
144
|
+
topSeriesCount: topSeries.length,
|
|
145
|
+
});
|
|
146
|
+
return {
|
|
147
|
+
query: input.query,
|
|
148
|
+
breakdownBy: input.breakdownBy,
|
|
149
|
+
dateResolution,
|
|
150
|
+
topSeries,
|
|
151
|
+
...(otherAggregated ? { otherAggregated } : {}),
|
|
152
|
+
seriesCount: allSeries.length,
|
|
153
|
+
};
|
|
154
|
+
},
|
|
155
|
+
format: (result) => {
|
|
156
|
+
const lines = [
|
|
157
|
+
`## GDELT Coverage Breakdown by ${result.breakdownBy === 'language' ? 'Language' : 'Country'}`,
|
|
158
|
+
`**Query:** ${result.query}`,
|
|
159
|
+
`**Total series:** ${result.seriesCount} | **Showing top:** ${result.topSeries.length}`,
|
|
160
|
+
`**Date Resolution:** ${result.dateResolution}`,
|
|
161
|
+
];
|
|
162
|
+
if (result.notice)
|
|
163
|
+
lines.push(`\n> ${result.notice}`);
|
|
164
|
+
for (const s of result.topSeries) {
|
|
165
|
+
const total = s.data.reduce((sum, d) => sum + d.value, 0);
|
|
166
|
+
lines.push(`\n### ${s.label} (total: ${total.toFixed(2)})`);
|
|
167
|
+
lines.push(`Data points: ${s.data.length}`);
|
|
168
|
+
const peak = s.data.reduce((max, d) => (d.value > max.value ? d : max), s.data[0] ?? { date: '', value: 0 });
|
|
169
|
+
if (peak.date)
|
|
170
|
+
lines.push(`Peak: ${peak.value.toFixed(3)} at ${peak.date}`);
|
|
171
|
+
}
|
|
172
|
+
if (result.otherAggregated) {
|
|
173
|
+
const otherTotal = result.otherAggregated.reduce((sum, d) => sum + d.value, 0);
|
|
174
|
+
const otherPeak = result.otherAggregated.reduce((max, d) => (d.value > max.value ? d : max), result.otherAggregated[0] ?? { date: '', value: 0 });
|
|
175
|
+
lines.push(`\n### Other (${result.seriesCount - result.topSeries.length} series, total: ${otherTotal.toFixed(2)})`);
|
|
176
|
+
if (otherPeak.date)
|
|
177
|
+
lines.push(`Peak: ${otherPeak.value.toFixed(3)} at ${otherPeak.date}`);
|
|
178
|
+
}
|
|
179
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
180
|
+
},
|
|
181
|
+
});
|
|
182
|
+
//# sourceMappingURL=get-coverage-breakdown.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-coverage-breakdown.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-coverage-breakdown.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT coverage timeline tool. Retrieves time series of coverage volume
|
|
3
|
+
* or average tone for a query using the GDELT DOC API.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-coverage-timeline.tool
|
|
5
|
+
*/
|
|
6
|
+
import { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
export declare const gdeltGetCoverageTimeline: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
9
|
+
query: z.ZodString;
|
|
10
|
+
mode: z.ZodDefault<z.ZodEnum<{
|
|
11
|
+
volume: "volume";
|
|
12
|
+
volume_with_articles: "volume_with_articles";
|
|
13
|
+
tone: "tone";
|
|
14
|
+
}>>;
|
|
15
|
+
timespan: z.ZodOptional<z.ZodString>;
|
|
16
|
+
startDatetime: z.ZodOptional<z.ZodString>;
|
|
17
|
+
endDatetime: z.ZodOptional<z.ZodString>;
|
|
18
|
+
smoothing: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
20
|
+
query: z.ZodString;
|
|
21
|
+
mode: z.ZodEnum<{
|
|
22
|
+
volume: "volume";
|
|
23
|
+
volume_with_articles: "volume_with_articles";
|
|
24
|
+
tone: "tone";
|
|
25
|
+
}>;
|
|
26
|
+
dateResolution: z.ZodEnum<{
|
|
27
|
+
hour: "hour";
|
|
28
|
+
day: "day";
|
|
29
|
+
}>;
|
|
30
|
+
series: z.ZodArray<z.ZodObject<{
|
|
31
|
+
label: z.ZodString;
|
|
32
|
+
data: z.ZodArray<z.ZodObject<{
|
|
33
|
+
date: z.ZodString;
|
|
34
|
+
value: z.ZodNumber;
|
|
35
|
+
articles: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
36
|
+
url: z.ZodString;
|
|
37
|
+
title: z.ZodString;
|
|
38
|
+
}, z.core.$strip>>>;
|
|
39
|
+
}, z.core.$strip>>;
|
|
40
|
+
}, z.core.$strip>>;
|
|
41
|
+
notice: z.ZodOptional<z.ZodString>;
|
|
42
|
+
}, z.core.$strip>, readonly [{
|
|
43
|
+
readonly reason: "no_timeline_data";
|
|
44
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
45
|
+
readonly when: "No timeline data returned for the query and time range.";
|
|
46
|
+
readonly recovery: "Broaden the query, extend the timespan, or verify query operators are correct.";
|
|
47
|
+
}, {
|
|
48
|
+
readonly reason: "gdelt_unavailable";
|
|
49
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
50
|
+
readonly when: "GDELT DOC API is unreachable or rate-limited.";
|
|
51
|
+
readonly retryable: true;
|
|
52
|
+
readonly recovery: "Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.";
|
|
53
|
+
}]>;
|
|
54
|
+
//# sourceMappingURL=get-coverage-timeline.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-coverage-timeline.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-coverage-timeline.tool.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAIjE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsMnC,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview GDELT coverage timeline tool. Retrieves time series of coverage volume
|
|
3
|
+
* or average tone for a query using the GDELT DOC API.
|
|
4
|
+
* @module mcp-server/tools/definitions/get-coverage-timeline.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
|
+
import { inferDateResolution } from '../date-resolution.js';
|
|
10
|
+
export const gdeltGetCoverageTimeline = tool('gdelt_get_coverage_timeline', {
|
|
11
|
+
title: 'Get GDELT Coverage Timeline',
|
|
12
|
+
description: 'Retrieve a time series showing when news coverage of a topic spiked, or how average tone shifted over time. ' +
|
|
13
|
+
'Use mode "volume" for normalized coverage intensity (% of all global coverage per timestep). ' +
|
|
14
|
+
'Use mode "volume_with_articles" for the same signal plus the top articles that drove each spike — ' +
|
|
15
|
+
'this is the primary signal-detection mode: a single call reveals both the spike and its cause, ' +
|
|
16
|
+
'avoiding a follow-up gdelt_search_articles call. ' +
|
|
17
|
+
'Use mode "tone" for average sentiment score per timestep (negative = hostile/fearful, positive = celebratory). ' +
|
|
18
|
+
'Date resolution is automatically chosen based on timespan: hours for short windows, days for longer ones. ' +
|
|
19
|
+
'Note: DOC API covers only the last 3 months.',
|
|
20
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
21
|
+
errors: [
|
|
22
|
+
{
|
|
23
|
+
reason: 'no_timeline_data',
|
|
24
|
+
code: JsonRpcErrorCode.NotFound,
|
|
25
|
+
when: 'No timeline data returned for the query and time range.',
|
|
26
|
+
recovery: 'Broaden the query, extend the timespan, or verify query operators are correct.',
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
reason: 'gdelt_unavailable',
|
|
30
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
31
|
+
when: 'GDELT DOC API is unreachable or rate-limited.',
|
|
32
|
+
retryable: true,
|
|
33
|
+
recovery: 'Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
input: z.object({
|
|
37
|
+
query: z
|
|
38
|
+
.string()
|
|
39
|
+
.min(1)
|
|
40
|
+
.describe('Search query using GDELT syntax. Same operators as gdelt_search_articles: ' +
|
|
41
|
+
'phrases, boolean OR, sourcecountry:, sourcelang:, domain:, theme:, tone<.'),
|
|
42
|
+
mode: z
|
|
43
|
+
.enum(['volume', 'volume_with_articles', 'tone'])
|
|
44
|
+
.default('volume')
|
|
45
|
+
.describe('Timeline mode: "volume" returns normalized coverage % per timestep, ' +
|
|
46
|
+
'"volume_with_articles" returns volume plus top articles per spike (best for signal detection), ' +
|
|
47
|
+
'"tone" returns average sentiment score per timestep.'),
|
|
48
|
+
timespan: z
|
|
49
|
+
.string()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Time window relative to now, e.g. "24h", "7d", "1m". ' +
|
|
52
|
+
'Ignored when startDatetime/endDatetime are set. Maximum 3 months.'),
|
|
53
|
+
startDatetime: z
|
|
54
|
+
.string()
|
|
55
|
+
.optional()
|
|
56
|
+
.describe('Start datetime in GDELT format YYYYMMDDHHMMSS. Must pair with endDatetime.'),
|
|
57
|
+
endDatetime: z
|
|
58
|
+
.string()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('End datetime in GDELT format YYYYMMDDHHMMSS. Must pair with startDatetime.'),
|
|
61
|
+
smoothing: z
|
|
62
|
+
.number()
|
|
63
|
+
.int()
|
|
64
|
+
.min(0)
|
|
65
|
+
.max(5)
|
|
66
|
+
.optional()
|
|
67
|
+
.describe('Smoothing window in timesteps (0 = none, 1–5 = moving average width). ' +
|
|
68
|
+
'Reduces noise for spotty topics.'),
|
|
69
|
+
}),
|
|
70
|
+
output: z.object({
|
|
71
|
+
query: z.string().describe('Echoed query string.'),
|
|
72
|
+
mode: z.enum(['volume', 'volume_with_articles', 'tone']).describe('Timeline mode used.'),
|
|
73
|
+
dateResolution: z
|
|
74
|
+
.enum(['hour', 'day'])
|
|
75
|
+
.describe('Temporal resolution of the data points — hour for short windows, day for longer.'),
|
|
76
|
+
series: z
|
|
77
|
+
.array(z
|
|
78
|
+
.object({
|
|
79
|
+
label: z.string().describe('Series label (e.g. "Volume Intensity" or "Average Tone").'),
|
|
80
|
+
data: z
|
|
81
|
+
.array(z
|
|
82
|
+
.object({
|
|
83
|
+
date: z.string().describe('Timestep in ISO 8601 format.'),
|
|
84
|
+
value: z
|
|
85
|
+
.number()
|
|
86
|
+
.describe('Normalized coverage % (volume mode) or average tone score (tone mode). ' +
|
|
87
|
+
'Tone range is approximately -100 to +100.'),
|
|
88
|
+
articles: z
|
|
89
|
+
.array(z
|
|
90
|
+
.object({
|
|
91
|
+
url: z.string().describe('Article URL.'),
|
|
92
|
+
title: z.string().describe('Article title.'),
|
|
93
|
+
})
|
|
94
|
+
.describe('An article linked to this spike.'))
|
|
95
|
+
.optional()
|
|
96
|
+
.describe('Top articles driving coverage at this timestep. Present only in volume_with_articles mode.'),
|
|
97
|
+
})
|
|
98
|
+
.describe('A single time-series data point.'))
|
|
99
|
+
.describe('Time-ordered data points for this series.'),
|
|
100
|
+
})
|
|
101
|
+
.describe('A single time series with a label and data points.'))
|
|
102
|
+
.describe('One or more time series (typically one for volume/tone, one per label for breakdowns).'),
|
|
103
|
+
notice: z
|
|
104
|
+
.string()
|
|
105
|
+
.optional()
|
|
106
|
+
.describe('Recovery hint when no data was returned. Absent on successful responses.'),
|
|
107
|
+
}),
|
|
108
|
+
async handler(input, ctx) {
|
|
109
|
+
ctx.log.info('gdelt_get_coverage_timeline', { query: input.query, mode: input.mode });
|
|
110
|
+
const svc = getGdeltDocService();
|
|
111
|
+
const modeMap = {
|
|
112
|
+
volume: 'timelinevol',
|
|
113
|
+
volume_with_articles: 'timelinevolinfo',
|
|
114
|
+
tone: 'timelinetone',
|
|
115
|
+
};
|
|
116
|
+
const series = await svc.getTimeline({
|
|
117
|
+
query: input.query,
|
|
118
|
+
mode: modeMap[input.mode],
|
|
119
|
+
...(input.timespan && { timespan: input.timespan }),
|
|
120
|
+
...(input.startDatetime && { startDatetime: input.startDatetime }),
|
|
121
|
+
...(input.endDatetime && { endDatetime: input.endDatetime }),
|
|
122
|
+
...(input.smoothing != null && { smoothing: input.smoothing }),
|
|
123
|
+
}, ctx);
|
|
124
|
+
if (series.length === 0 || series.every((s) => s.data.length === 0)) {
|
|
125
|
+
throw ctx.fail('no_timeline_data', `No timeline data for "${input.query}"`, {
|
|
126
|
+
recovery: {
|
|
127
|
+
hint: `No coverage data found for "${input.query}". Try broadening the query or extending the time window.`,
|
|
128
|
+
},
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// Infer date resolution from data point spacing
|
|
132
|
+
const allDates = series.flatMap((s) => s.data.map((d) => d.date));
|
|
133
|
+
const dateResolution = inferDateResolution(allDates);
|
|
134
|
+
ctx.log.info('gdelt_get_coverage_timeline completed', {
|
|
135
|
+
seriesCount: series.length,
|
|
136
|
+
pointCount: series[0]?.data.length ?? 0,
|
|
137
|
+
});
|
|
138
|
+
return { query: input.query, mode: input.mode, dateResolution, series };
|
|
139
|
+
},
|
|
140
|
+
format: (result) => {
|
|
141
|
+
const lines = [
|
|
142
|
+
`## GDELT Coverage Timeline`,
|
|
143
|
+
`**Query:** ${result.query}`,
|
|
144
|
+
`**Mode:** ${result.mode}`,
|
|
145
|
+
`**Date Resolution:** ${result.dateResolution}`,
|
|
146
|
+
];
|
|
147
|
+
if (result.notice)
|
|
148
|
+
lines.push(`\n> ${result.notice}`);
|
|
149
|
+
for (const s of result.series) {
|
|
150
|
+
lines.push(`\n### ${s.label}`);
|
|
151
|
+
const peakPoint = s.data.reduce((max, d) => (Math.abs(d.value) > Math.abs(max.value) ? d : max), s.data[0] ?? { date: '', value: 0, articles: undefined });
|
|
152
|
+
lines.push(`**Data points:** ${s.data.length}`);
|
|
153
|
+
if (peakPoint.date) {
|
|
154
|
+
lines.push(`**Peak:** ${peakPoint.value.toFixed(3)} at ${peakPoint.date}`);
|
|
155
|
+
}
|
|
156
|
+
// Show first 10 data points to orient the agent
|
|
157
|
+
const preview = s.data.slice(0, 10);
|
|
158
|
+
for (const d of preview) {
|
|
159
|
+
const articlesNote = d.articles?.length ? ` (${d.articles.length} articles)` : '';
|
|
160
|
+
lines.push(`- ${d.date}: ${d.value.toFixed(3)}${articlesNote}`);
|
|
161
|
+
if (d.articles?.length) {
|
|
162
|
+
for (const a of d.articles.slice(0, 3)) {
|
|
163
|
+
lines.push(` - [${a.title}](${a.url})`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (s.data.length > 10)
|
|
168
|
+
lines.push(`- … ${s.data.length - 10} more points`);
|
|
169
|
+
}
|
|
170
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
171
|
+
},
|
|
172
|
+
});
|
|
173
|
+
//# sourceMappingURL=get-coverage-timeline.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-coverage-timeline.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-coverage-timeline.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,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC,6BAA6B,EAAE;IAC1E,KAAK,EAAE,6BAA6B;IACpC,WAAW,EACT,8GAA8G;QAC9G,+FAA+F;QAC/F,oGAAoG;QACpG,iGAAiG;QACjG,mDAAmD;QACnD,iHAAiH;QACjH,4GAA4G;QAC5G,8CAA8C;IAChD,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;IAExD,MAAM,EAAE;QACN;YACE,MAAM,EAAE,kBAAkB;YAC1B,IAAI,EAAE,gBAAgB,CAAC,QAAQ;YAC/B,IAAI,EAAE,yDAAyD;YAC/D,QAAQ,EAAE,gFAAgF;SAC3F;QACD;YACE,MAAM,EAAE,mBAAmB;YAC3B,IAAI,EAAE,gBAAgB,CAAC,kBAAkB;YACzC,IAAI,EAAE,+CAA+C;YACrD,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,4EAA4E;YAC1E,2EAA2E,CAC9E;QACH,IAAI,EAAE,CAAC;aACJ,IAAI,CAAC,CAAC,QAAQ,EAAE,sBAAsB,EAAE,MAAM,CAAC,CAAC;aAChD,OAAO,CAAC,QAAQ,CAAC;aACjB,QAAQ,CACP,sEAAsE;YACpE,iGAAiG;YACjG,sDAAsD,CACzD;QACH,QAAQ,EAAE,CAAC;aACR,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,uDAAuD;YACrD,mEAAmE,CACtE;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,SAAS,EAAE,CAAC;aACT,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,EAAE;aACV,QAAQ,CACP,wEAAwE;YACtE,kCAAkC,CACrC;KACJ,CAAC;IAEF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QAClD,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,sBAAsB,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,qBAAqB,CAAC;QACxF,cAAc,EAAE,CAAC;aACd,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;aACrB,QAAQ,CAAC,kFAAkF,CAAC;QAC/F,MAAM,EAAE,CAAC;aACN,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;YACvF,IAAI,EAAE,CAAC;iBACJ,KAAK,CACJ,CAAC;iBACE,MAAM,CAAC;gBACN,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;gBACzD,KAAK,EAAE,CAAC;qBACL,MAAM,EAAE;qBACR,QAAQ,CACP,yEAAyE;oBACvE,2CAA2C,CAC9C;gBACH,QAAQ,EAAE,CAAC;qBACR,KAAK,CACJ,CAAC;qBACE,MAAM,CAAC;oBACN,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC;oBACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;iBAC7C,CAAC;qBACD,QAAQ,CAAC,kCAAkC,CAAC,CAChD;qBACA,QAAQ,EAAE;qBACV,QAAQ,CACP,4FAA4F,CAC7F;aACJ,CAAC;iBACD,QAAQ,CAAC,kCAAkC,CAAC,CAChD;iBACA,QAAQ,CAAC,2CAA2C,CAAC;SACzD,CAAC;aACD,QAAQ,CAAC,oDAAoD,CAAC,CAClE;aACA,QAAQ,CACP,wFAAwF,CACzF;QACH,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0EAA0E,CAAC;KACxF,CAAC;IAEF,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,6BAA6B,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;QACtF,MAAM,GAAG,GAAG,kBAAkB,EAAE,CAAC;QAEjC,MAAM,OAAO,GAAG;YACd,MAAM,EAAE,aAAa;YACrB,oBAAoB,EAAE,iBAAiB;YACvC,IAAI,EAAE,cAAc;SACZ,CAAC;QAEX,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,WAAW,CAClC;YACE,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;YACzB,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,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;SAC/D,EACD,GAAG,CACJ,CAAC;QAEF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;YACpE,MAAM,GAAG,CAAC,IAAI,CAAC,kBAAkB,EAAE,yBAAyB,KAAK,CAAC,KAAK,GAAG,EAAE;gBAC1E,QAAQ,EAAE;oBACR,IAAI,EAAE,+BAA+B,KAAK,CAAC,KAAK,2DAA2D;iBAC5G;aACF,CAAC,CAAC;QACL,CAAC;QAED,gDAAgD;QAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAClE,MAAM,cAAc,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAErD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,uCAAuC,EAAE;YACpD,WAAW,EAAE,MAAM,CAAC,MAAM;YAC1B,UAAU,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC;SACxC,CAAC,CAAC;QAEH,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;IAC1E,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,KAAK,GAAa;YACtB,4BAA4B;YAC5B,cAAc,MAAM,CAAC,KAAK,EAAE;YAC5B,aAAa,MAAM,CAAC,IAAI,EAAE;YAC1B,wBAAwB,MAAM,CAAC,cAAc,EAAE;SAChD,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,MAAM,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YAC/B,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAC7B,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAC/D,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CACzD,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;YAChD,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;gBACnB,KAAK,CAAC,IAAI,CAAC,aAAa,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7E,CAAC;YACD,gDAAgD;YAChD,MAAM,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,MAAM,YAAY,GAAG,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;gBAClF,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,YAAY,EAAE,CAAC,CAAC;gBAChE,IAAI,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;oBACvB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;wBACvC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC;oBAC3C,CAAC;gBACH,CAAC;YACH,CAAC;YACD,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE;gBAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,cAAc,CAAC,CAAC;QAC9E,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,41 @@
|
|
|
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 { z } from '@cyanheads/mcp-ts-core';
|
|
7
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
8
|
+
export declare const gdeltGetToneDistribution: import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
|
|
9
|
+
query: z.ZodString;
|
|
10
|
+
timespan: z.ZodOptional<z.ZodString>;
|
|
11
|
+
startDatetime: z.ZodOptional<z.ZodString>;
|
|
12
|
+
endDatetime: z.ZodOptional<z.ZodString>;
|
|
13
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
14
|
+
query: z.ZodString;
|
|
15
|
+
histogram: z.ZodArray<z.ZodObject<{
|
|
16
|
+
bin: z.ZodNumber;
|
|
17
|
+
count: z.ZodNumber;
|
|
18
|
+
articles: z.ZodArray<z.ZodObject<{
|
|
19
|
+
url: z.ZodString;
|
|
20
|
+
title: z.ZodString;
|
|
21
|
+
}, z.core.$strip>>;
|
|
22
|
+
}, z.core.$strip>>;
|
|
23
|
+
summary: z.ZodObject<{
|
|
24
|
+
peakNegativeBin: z.ZodNumber;
|
|
25
|
+
peakPositiveBin: z.ZodNumber;
|
|
26
|
+
neutralPct: z.ZodNumber;
|
|
27
|
+
}, z.core.$strip>;
|
|
28
|
+
notice: z.ZodOptional<z.ZodString>;
|
|
29
|
+
}, z.core.$strip>, readonly [{
|
|
30
|
+
readonly reason: "no_tone_data";
|
|
31
|
+
readonly code: JsonRpcErrorCode.NotFound;
|
|
32
|
+
readonly when: "No tone histogram data returned for the query.";
|
|
33
|
+
readonly recovery: "Broaden the query or extend the timespan to include more matching articles.";
|
|
34
|
+
}, {
|
|
35
|
+
readonly reason: "gdelt_unavailable";
|
|
36
|
+
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
37
|
+
readonly when: "GDELT DOC API is unreachable or rate-limited.";
|
|
38
|
+
readonly retryable: true;
|
|
39
|
+
readonly recovery: "Wait at least 5 seconds before retrying — GDELT enforces 1 request per 5 seconds.";
|
|
40
|
+
}]>;
|
|
41
|
+
//# sourceMappingURL=get-tone-distribution.tool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-tone-distribution.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-tone-distribution.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,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiKnC,CAAC"}
|