euparliamentmonitor 0.8.36 → 0.8.39
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 +1 -1
- package/package.json +2 -2
- package/scripts/generators/pipeline/fetch-stage.d.ts +25 -17
- package/scripts/generators/pipeline/fetch-stage.js +129 -148
- package/scripts/index.d.ts +3 -0
- package/scripts/index.js +5 -0
- package/scripts/mcp/ep-mcp-client.d.ts +52 -6
- package/scripts/mcp/ep-mcp-client.js +169 -9
- package/scripts/mcp/imf-mcp-client.d.ts +231 -0
- package/scripts/mcp/imf-mcp-client.js +507 -0
- package/scripts/types/imf.d.ts +221 -0
- package/scripts/types/imf.js +4 -0
- package/scripts/types/index.d.ts +1 -0
- package/scripts/types/mcp.d.ts +46 -25
- package/scripts/utils/content-validator.d.ts +65 -0
- package/scripts/utils/content-validator.js +129 -0
- package/scripts/utils/imf-data.d.ts +216 -0
- package/scripts/utils/imf-data.js +577 -0
- package/scripts/utils/validate-analysis-completeness.js +140 -20
- package/scripts/utils/validate-articles.js +42 -33
package/README.md
CHANGED
|
@@ -124,7 +124,7 @@ import {
|
|
|
124
124
|
|
|
125
125
|
**MCP Server Integration**: The project uses the
|
|
126
126
|
[European-Parliament-MCP-Server](https://github.com/Hack23/European-Parliament-MCP-Server)
|
|
127
|
-
v1.2.
|
|
127
|
+
v1.2.10 for accessing real EU Parliament data via the Model Context Protocol.
|
|
128
128
|
|
|
129
129
|
- **MCP Server Status**: ✅ Fully operational — 60+ EP data tools available
|
|
130
130
|
(feeds, direct lookups, analytical tools, intelligence correlation)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "euparliamentmonitor",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.39",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "European Parliament Intelligence Platform - Monitor political activity with systematic transparency",
|
|
6
6
|
"main": "scripts/index.js",
|
|
@@ -171,7 +171,7 @@
|
|
|
171
171
|
"node": ">=25"
|
|
172
172
|
},
|
|
173
173
|
"dependencies": {
|
|
174
|
-
"european-parliament-mcp-server": "1.2.
|
|
174
|
+
"european-parliament-mcp-server": "1.2.10"
|
|
175
175
|
},
|
|
176
176
|
"optionalDependencies": {
|
|
177
177
|
"worldbank-mcp": "1.0.1"
|
|
@@ -271,40 +271,42 @@ export declare function fetchMEPsFeedWithTotal(client: EuropeanParliamentMCPClie
|
|
|
271
271
|
}>;
|
|
272
272
|
/**
|
|
273
273
|
* Fetch documents feed from MCP.
|
|
274
|
-
*
|
|
274
|
+
* The underlying EP MCP `get_documents_feed` tool serves a server-defined
|
|
275
|
+
* fixed window and ignores any `timeframe` parameter; the parameter is kept
|
|
276
|
+
* on this function's signature for backwards compatibility with callers.
|
|
275
277
|
*
|
|
276
278
|
* @param client - MCP client or null
|
|
277
|
-
* @param
|
|
279
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
278
280
|
* @returns Array of document feed items
|
|
279
281
|
*/
|
|
280
|
-
export declare function fetchDocumentsFeed(client: EuropeanParliamentMCPClient | null,
|
|
282
|
+
export declare function fetchDocumentsFeed(client: EuropeanParliamentMCPClient | null, _timeframe?: FeedTimeframe): Promise<DocumentFeedItem[]>;
|
|
281
283
|
/**
|
|
282
284
|
* Fetch plenary documents feed from MCP.
|
|
283
|
-
*
|
|
285
|
+
* Fixed-window feed; `timeframe` is ignored by the server.
|
|
284
286
|
*
|
|
285
287
|
* @param client - MCP client or null
|
|
286
|
-
* @param
|
|
288
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
287
289
|
* @returns Array of document feed items
|
|
288
290
|
*/
|
|
289
|
-
export declare function fetchPlenaryDocumentsFeed(client: EuropeanParliamentMCPClient | null,
|
|
291
|
+
export declare function fetchPlenaryDocumentsFeed(client: EuropeanParliamentMCPClient | null, _timeframe?: FeedTimeframe): Promise<DocumentFeedItem[]>;
|
|
290
292
|
/**
|
|
291
293
|
* Fetch committee documents feed from MCP.
|
|
292
|
-
*
|
|
294
|
+
* Fixed-window feed; `timeframe` is ignored by the server.
|
|
293
295
|
*
|
|
294
296
|
* @param client - MCP client or null
|
|
295
|
-
* @param
|
|
297
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
296
298
|
* @returns Array of document feed items
|
|
297
299
|
*/
|
|
298
|
-
export declare function fetchCommitteeDocumentsFeed(client: EuropeanParliamentMCPClient | null,
|
|
300
|
+
export declare function fetchCommitteeDocumentsFeed(client: EuropeanParliamentMCPClient | null, _timeframe?: FeedTimeframe): Promise<DocumentFeedItem[]>;
|
|
299
301
|
/**
|
|
300
302
|
* Fetch plenary session documents feed from MCP.
|
|
301
|
-
*
|
|
303
|
+
* Fixed-window feed; `timeframe` is ignored by the server.
|
|
302
304
|
*
|
|
303
305
|
* @param client - MCP client or null
|
|
304
|
-
* @param
|
|
306
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
305
307
|
* @returns Array of document feed items
|
|
306
308
|
*/
|
|
307
|
-
export declare function fetchPlenarySessionDocumentsFeed(client: EuropeanParliamentMCPClient | null,
|
|
309
|
+
export declare function fetchPlenarySessionDocumentsFeed(client: EuropeanParliamentMCPClient | null, _timeframe?: FeedTimeframe): Promise<DocumentFeedItem[]>;
|
|
308
310
|
/**
|
|
309
311
|
* Fetch external documents feed from MCP.
|
|
310
312
|
* Falls back to a wider timeframe when the initial timeframe returns no data.
|
|
@@ -316,13 +318,13 @@ export declare function fetchPlenarySessionDocumentsFeed(client: EuropeanParliam
|
|
|
316
318
|
export declare function fetchExternalDocumentsFeed(client: EuropeanParliamentMCPClient | null, timeframe?: FeedTimeframe): Promise<DocumentFeedItem[]>;
|
|
317
319
|
/**
|
|
318
320
|
* Fetch parliamentary questions feed from MCP.
|
|
319
|
-
*
|
|
321
|
+
* Fixed-window feed; `timeframe` is ignored by the server.
|
|
320
322
|
*
|
|
321
323
|
* @param client - MCP client or null
|
|
322
|
-
* @param
|
|
324
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
323
325
|
* @returns Array of question feed items
|
|
324
326
|
*/
|
|
325
|
-
export declare function fetchQuestionsFeed(client: EuropeanParliamentMCPClient | null,
|
|
327
|
+
export declare function fetchQuestionsFeed(client: EuropeanParliamentMCPClient | null, _timeframe?: FeedTimeframe): Promise<QuestionFeedItem[]>;
|
|
326
328
|
/**
|
|
327
329
|
* Fetch MEP declarations feed from MCP.
|
|
328
330
|
*
|
|
@@ -334,11 +336,17 @@ export declare function fetchDeclarationsFeed(client: EuropeanParliamentMCPClien
|
|
|
334
336
|
/**
|
|
335
337
|
* Fetch corporate bodies feed from MCP.
|
|
336
338
|
*
|
|
339
|
+
* `_timeframe` is retained only for signature compatibility with sliding-window
|
|
340
|
+
* fetchers (so the shared `fetchEPFeedData` orchestrator can dispatch uniformly);
|
|
341
|
+
* the EP MCP server serves a server-defined fixed window for this feed and
|
|
342
|
+
* ignores any timeframe input (as of v1.2.10; pre-v1.2.10 it rejected with
|
|
343
|
+
* `INVALID_PARAMS` — see Hack23/European-Parliament-MCP-Server#377).
|
|
344
|
+
*
|
|
337
345
|
* @param client - MCP client or null
|
|
338
|
-
* @param
|
|
346
|
+
* @param _timeframe - Ignored by the server; kept for signature compatibility
|
|
339
347
|
* @returns Array of corporate body feed items
|
|
340
348
|
*/
|
|
341
|
-
export declare function fetchCorporateBodiesFeed(client: EuropeanParliamentMCPClient | null,
|
|
349
|
+
export declare function fetchCorporateBodiesFeed(client: EuropeanParliamentMCPClient | null, _timeframe?: FeedTimeframe): Promise<CorporateBodyFeedItem[]>;
|
|
342
350
|
/**
|
|
343
351
|
* Fetch all EP feed data for breaking news articles.
|
|
344
352
|
* Calls adopted texts, events, procedures, and MEPs feeds in parallel.
|
|
@@ -1084,6 +1084,32 @@ class UpstreamTimeoutError extends Error {
|
|
|
1084
1084
|
this.name = 'UpstreamTimeoutError';
|
|
1085
1085
|
}
|
|
1086
1086
|
}
|
|
1087
|
+
/**
|
|
1088
|
+
* Error thrown when the EP MCP server returns a response indicating the feed
|
|
1089
|
+
* is unavailable (uniform `{status:"unavailable"}` envelope or the legacy raw
|
|
1090
|
+
* upstream 404 envelope historically emitted pre-v1.2.10). Distinct from
|
|
1091
|
+
* {@link UpstreamTimeoutError} so logs/diagnostics do not misattribute a
|
|
1092
|
+
* 404/unavailable response to a timeout. Shares the same control-flow role —
|
|
1093
|
+
* callers treat it as "stop the timeframe-widening retry loop and return the
|
|
1094
|
+
* empty sentinel".
|
|
1095
|
+
*/
|
|
1096
|
+
class FeedUnavailableError extends Error {
|
|
1097
|
+
constructor(toolName) {
|
|
1098
|
+
super(`EP MCP feed unavailable for ${toolName} — treating as known-empty`);
|
|
1099
|
+
this.name = 'FeedUnavailableError';
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Type guard: returns `true` for either error type that should stop the
|
|
1104
|
+
* timeframe-widening retry loop ({@link UpstreamTimeoutError} or
|
|
1105
|
+
* {@link FeedUnavailableError}).
|
|
1106
|
+
*
|
|
1107
|
+
* @param error - Caught error value
|
|
1108
|
+
* @returns `true` when the caller should stop retrying and return the empty sentinel
|
|
1109
|
+
*/
|
|
1110
|
+
function isStopRetryError(error) {
|
|
1111
|
+
return error instanceof UpstreamTimeoutError || error instanceof FeedUnavailableError;
|
|
1112
|
+
}
|
|
1087
1113
|
/**
|
|
1088
1114
|
* Check whether a parsed MCP response envelope indicates an upstream timeout
|
|
1089
1115
|
* and throw {@link UpstreamTimeoutError} if so. The EP MCP server returns
|
|
@@ -1105,6 +1131,26 @@ function checkUpstreamTimeout(value) {
|
|
|
1105
1131
|
'Consider using year-based endpoints as fallback.');
|
|
1106
1132
|
throw new UpstreamTimeoutError(toolName);
|
|
1107
1133
|
}
|
|
1134
|
+
// Defensive detection of the legacy raw upstream 404 shape that pre-v1.2.10
|
|
1135
|
+
// get_events_feed / get_procedures_feed emitted
|
|
1136
|
+
// (Hack23/European-Parliament-MCP-Server#378, closed by PR #380 in
|
|
1137
|
+
// v1.2.10). Shape:
|
|
1138
|
+
// {"@id":"https://data.europarl.europa.eu/eli/dl/...", "error":"404 N..."}
|
|
1139
|
+
// Treated identically to the uniform `{status:"unavailable"}` envelope —
|
|
1140
|
+
// i.e. stop timeframe-widening retry loops instead of silently returning [].
|
|
1141
|
+
// Retained as belt-and-braces so older pinned server versions (or any future
|
|
1142
|
+
// regression) do not bypass the NOT_FOUND bookkeeping done by the EP MCP
|
|
1143
|
+
// client's safeCallTool.
|
|
1144
|
+
const idField = envelope['@id'];
|
|
1145
|
+
const errorField = envelope['error'];
|
|
1146
|
+
if (typeof idField === 'string' &&
|
|
1147
|
+
idField.startsWith('https://data.europarl.europa.eu/') &&
|
|
1148
|
+
typeof errorField === 'string' &&
|
|
1149
|
+
errorField.includes('404')) {
|
|
1150
|
+
console.warn(`${WARN_PREFIX} EP MCP returned raw upstream 404 shape — treating feed as unavailable ` +
|
|
1151
|
+
'(upstream #378). This should have been caught earlier as a NOT_FOUND failure.');
|
|
1152
|
+
throw new FeedUnavailableError('raw_404_envelope');
|
|
1153
|
+
}
|
|
1108
1154
|
}
|
|
1109
1155
|
/**
|
|
1110
1156
|
* Handle errors from feed-fetching functions with timeframe-widening logic.
|
|
@@ -1118,7 +1164,7 @@ function checkUpstreamTimeout(value) {
|
|
|
1118
1164
|
* @returns A wider {@link FeedTimeframe} to retry, or `undefined` to stop
|
|
1119
1165
|
*/
|
|
1120
1166
|
function handleFeedFetchError(error, tf, toolName) {
|
|
1121
|
-
if (error
|
|
1167
|
+
if (isStopRetryError(error))
|
|
1122
1168
|
return undefined;
|
|
1123
1169
|
const message = error instanceof Error ? error.message : String(error);
|
|
1124
1170
|
const wider = getWiderTimeframe(tf);
|
|
@@ -1378,152 +1424,101 @@ export async function fetchMEPsFeedWithTotal(client, timeframe = 'one-week') {
|
|
|
1378
1424
|
return { items, total };
|
|
1379
1425
|
}
|
|
1380
1426
|
catch (error) {
|
|
1381
|
-
if (error
|
|
1427
|
+
if (isStopRetryError(error))
|
|
1382
1428
|
return { items: [], total: 0 };
|
|
1383
1429
|
const message = error instanceof Error ? error.message : String(error);
|
|
1384
1430
|
console.warn(`${WARN_PREFIX} get_meps_feed failed:`, message);
|
|
1385
1431
|
return { items: [], total: 0 };
|
|
1386
1432
|
}
|
|
1387
1433
|
}
|
|
1434
|
+
/**
|
|
1435
|
+
* Fetch a fixed-window EP API v2 feed that ignores the `timeframe` parameter.
|
|
1436
|
+
*
|
|
1437
|
+
* The EP MCP server splits feed tools into two groups — sliding-window feeds
|
|
1438
|
+
* accept `timeframe`/`startDate`, fixed-window feeds (documents,
|
|
1439
|
+
* plenary_documents, committee_documents, plenary_session_documents,
|
|
1440
|
+
* parliamentary_questions, corporate_bodies, controlled_vocabularies) serve a
|
|
1441
|
+
* server-defined window. As of v1.2.10 the server silently ignores
|
|
1442
|
+
* `timeframe`/`startDate` on fixed-window tools
|
|
1443
|
+
* (Hack23/European-Parliament-MCP-Server#379); pre-v1.2.10 it rejected them
|
|
1444
|
+
* with `INVALID_PARAMS` (#377). This helper issues a single RPC either way —
|
|
1445
|
+
* there is no point in timeframe-widening retry loops because the server does
|
|
1446
|
+
* not narrow/widen results based on timeframe.
|
|
1447
|
+
*
|
|
1448
|
+
* @param client - MCP client (null returns `[]`)
|
|
1449
|
+
* @param toolName - Tool name for log messages
|
|
1450
|
+
* @param callFn - Callback that issues the feed RPC
|
|
1451
|
+
* @returns Array of mapped feed items (may be empty)
|
|
1452
|
+
*/
|
|
1453
|
+
async function fetchFixedWindowFeed(client, toolName, callFn) {
|
|
1454
|
+
if (!client)
|
|
1455
|
+
return [];
|
|
1456
|
+
try {
|
|
1457
|
+
console.log(`${MCP_FETCH_PREFIX} Fetching ${toolName}...`);
|
|
1458
|
+
const result = await callMCP(callFn, undefined, toolName);
|
|
1459
|
+
return parseFeedResult(result).map((item) => mapFeedItemBase(item));
|
|
1460
|
+
}
|
|
1461
|
+
catch (error) {
|
|
1462
|
+
if (isStopRetryError(error))
|
|
1463
|
+
return [];
|
|
1464
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1465
|
+
console.warn(`${WARN_PREFIX} ${toolName} failed:`, message);
|
|
1466
|
+
return [];
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1388
1469
|
/**
|
|
1389
1470
|
* Fetch documents feed from MCP.
|
|
1390
|
-
*
|
|
1471
|
+
* The underlying EP MCP `get_documents_feed` tool serves a server-defined
|
|
1472
|
+
* fixed window and ignores any `timeframe` parameter; the parameter is kept
|
|
1473
|
+
* on this function's signature for backwards compatibility with callers.
|
|
1391
1474
|
*
|
|
1392
1475
|
* @param client - MCP client or null
|
|
1393
|
-
* @param
|
|
1476
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
1394
1477
|
* @returns Array of document feed items
|
|
1395
1478
|
*/
|
|
1396
|
-
export async function fetchDocumentsFeed(client,
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
while (currentTimeframe) {
|
|
1401
|
-
const tf = currentTimeframe;
|
|
1402
|
-
try {
|
|
1403
|
-
console.log(`${MCP_FETCH_PREFIX} Fetching documents feed (${currentTimeframe})...`);
|
|
1404
|
-
const result = await callMCP(() => client.getDocumentsFeed({ timeframe: tf, limit: 20 }), undefined, 'get_documents_feed');
|
|
1405
|
-
const items = parseFeedResult(result).map((item) => mapFeedItemBase(item));
|
|
1406
|
-
if (items.length > 0 || !getWiderTimeframe(currentTimeframe))
|
|
1407
|
-
return items;
|
|
1408
|
-
console.log(`${INFO_PREFIX} documents feed empty for ${currentTimeframe}, widening timeframe...`);
|
|
1409
|
-
currentTimeframe = getWiderTimeframe(currentTimeframe);
|
|
1410
|
-
}
|
|
1411
|
-
catch (error) {
|
|
1412
|
-
const wider = handleFeedFetchError(error, tf, 'get_documents_feed');
|
|
1413
|
-
if (wider) {
|
|
1414
|
-
currentTimeframe = wider;
|
|
1415
|
-
}
|
|
1416
|
-
else {
|
|
1417
|
-
return [];
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
return [];
|
|
1479
|
+
export async function fetchDocumentsFeed(client,
|
|
1480
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1481
|
+
_timeframe = 'one-week') {
|
|
1482
|
+
return fetchFixedWindowFeed(client, 'get_documents_feed', () => client.getDocumentsFeed({ limit: 20 }));
|
|
1422
1483
|
}
|
|
1423
1484
|
/**
|
|
1424
1485
|
* Fetch plenary documents feed from MCP.
|
|
1425
|
-
*
|
|
1486
|
+
* Fixed-window feed; `timeframe` is ignored by the server.
|
|
1426
1487
|
*
|
|
1427
1488
|
* @param client - MCP client or null
|
|
1428
|
-
* @param
|
|
1489
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
1429
1490
|
* @returns Array of document feed items
|
|
1430
1491
|
*/
|
|
1431
|
-
export async function fetchPlenaryDocumentsFeed(client,
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
while (currentTimeframe) {
|
|
1436
|
-
const tf = currentTimeframe;
|
|
1437
|
-
try {
|
|
1438
|
-
console.log(`${MCP_FETCH_PREFIX} Fetching plenary documents feed (${currentTimeframe})...`);
|
|
1439
|
-
const result = await callMCP(() => client.getPlenaryDocumentsFeed({ timeframe: tf, limit: 20 }), undefined, 'get_plenary_documents_feed');
|
|
1440
|
-
const items = parseFeedResult(result).map((item) => mapFeedItemBase(item));
|
|
1441
|
-
if (items.length > 0 || !getWiderTimeframe(currentTimeframe))
|
|
1442
|
-
return items;
|
|
1443
|
-
console.log(`${INFO_PREFIX} plenary documents feed empty for ${currentTimeframe}, widening timeframe...`);
|
|
1444
|
-
currentTimeframe = getWiderTimeframe(currentTimeframe);
|
|
1445
|
-
}
|
|
1446
|
-
catch (error) {
|
|
1447
|
-
const wider = handleFeedFetchError(error, tf, 'get_plenary_documents_feed');
|
|
1448
|
-
if (wider) {
|
|
1449
|
-
currentTimeframe = wider;
|
|
1450
|
-
}
|
|
1451
|
-
else {
|
|
1452
|
-
return [];
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
return [];
|
|
1492
|
+
export async function fetchPlenaryDocumentsFeed(client,
|
|
1493
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1494
|
+
_timeframe = 'one-week') {
|
|
1495
|
+
return fetchFixedWindowFeed(client, 'get_plenary_documents_feed', () => client.getPlenaryDocumentsFeed({ limit: 20 }));
|
|
1457
1496
|
}
|
|
1458
1497
|
/**
|
|
1459
1498
|
* Fetch committee documents feed from MCP.
|
|
1460
|
-
*
|
|
1499
|
+
* Fixed-window feed; `timeframe` is ignored by the server.
|
|
1461
1500
|
*
|
|
1462
1501
|
* @param client - MCP client or null
|
|
1463
|
-
* @param
|
|
1502
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
1464
1503
|
* @returns Array of document feed items
|
|
1465
1504
|
*/
|
|
1466
|
-
export async function fetchCommitteeDocumentsFeed(client,
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
while (currentTimeframe) {
|
|
1471
|
-
const tf = currentTimeframe;
|
|
1472
|
-
try {
|
|
1473
|
-
console.log(`${MCP_FETCH_PREFIX} Fetching committee documents feed (${currentTimeframe})...`);
|
|
1474
|
-
const result = await callMCP(() => client.getCommitteeDocumentsFeed({ timeframe: tf, limit: 20 }), undefined, 'get_committee_documents_feed');
|
|
1475
|
-
const items = parseFeedResult(result).map((item) => mapFeedItemBase(item));
|
|
1476
|
-
if (items.length > 0 || !getWiderTimeframe(currentTimeframe))
|
|
1477
|
-
return items;
|
|
1478
|
-
console.log(`${INFO_PREFIX} committee documents feed empty for ${currentTimeframe}, widening timeframe...`);
|
|
1479
|
-
currentTimeframe = getWiderTimeframe(currentTimeframe);
|
|
1480
|
-
}
|
|
1481
|
-
catch (error) {
|
|
1482
|
-
const wider = handleFeedFetchError(error, tf, 'get_committee_documents_feed');
|
|
1483
|
-
if (wider) {
|
|
1484
|
-
currentTimeframe = wider;
|
|
1485
|
-
}
|
|
1486
|
-
else {
|
|
1487
|
-
return [];
|
|
1488
|
-
}
|
|
1489
|
-
}
|
|
1490
|
-
}
|
|
1491
|
-
return [];
|
|
1505
|
+
export async function fetchCommitteeDocumentsFeed(client,
|
|
1506
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1507
|
+
_timeframe = 'one-week') {
|
|
1508
|
+
return fetchFixedWindowFeed(client, 'get_committee_documents_feed', () => client.getCommitteeDocumentsFeed({ limit: 20 }));
|
|
1492
1509
|
}
|
|
1493
1510
|
/**
|
|
1494
1511
|
* Fetch plenary session documents feed from MCP.
|
|
1495
|
-
*
|
|
1512
|
+
* Fixed-window feed; `timeframe` is ignored by the server.
|
|
1496
1513
|
*
|
|
1497
1514
|
* @param client - MCP client or null
|
|
1498
|
-
* @param
|
|
1515
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
1499
1516
|
* @returns Array of document feed items
|
|
1500
1517
|
*/
|
|
1501
|
-
export async function fetchPlenarySessionDocumentsFeed(client,
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
while (currentTimeframe) {
|
|
1506
|
-
const tf = currentTimeframe;
|
|
1507
|
-
try {
|
|
1508
|
-
console.log(`${MCP_FETCH_PREFIX} Fetching plenary session documents feed (${currentTimeframe})...`);
|
|
1509
|
-
const result = await callMCP(() => client.getPlenarySessionDocumentsFeed({ timeframe: tf, limit: 20 }), undefined, 'get_plenary_session_documents_feed');
|
|
1510
|
-
const items = parseFeedResult(result).map((item) => mapFeedItemBase(item));
|
|
1511
|
-
if (items.length > 0 || !getWiderTimeframe(currentTimeframe))
|
|
1512
|
-
return items;
|
|
1513
|
-
console.log(`${INFO_PREFIX} plenary session docs feed empty for ${currentTimeframe}, widening timeframe...`);
|
|
1514
|
-
currentTimeframe = getWiderTimeframe(currentTimeframe);
|
|
1515
|
-
}
|
|
1516
|
-
catch (error) {
|
|
1517
|
-
const wider = handleFeedFetchError(error, tf, 'get_plenary_session_documents_feed');
|
|
1518
|
-
if (wider) {
|
|
1519
|
-
currentTimeframe = wider;
|
|
1520
|
-
}
|
|
1521
|
-
else {
|
|
1522
|
-
return [];
|
|
1523
|
-
}
|
|
1524
|
-
}
|
|
1525
|
-
}
|
|
1526
|
-
return [];
|
|
1518
|
+
export async function fetchPlenarySessionDocumentsFeed(client,
|
|
1519
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1520
|
+
_timeframe = 'one-week') {
|
|
1521
|
+
return fetchFixedWindowFeed(client, 'get_plenary_session_documents_feed', () => client.getPlenarySessionDocumentsFeed({ limit: 20 }));
|
|
1527
1522
|
}
|
|
1528
1523
|
/**
|
|
1529
1524
|
* Fetch external documents feed from MCP.
|
|
@@ -1562,38 +1557,16 @@ export async function fetchExternalDocumentsFeed(client, timeframe = 'one-week')
|
|
|
1562
1557
|
}
|
|
1563
1558
|
/**
|
|
1564
1559
|
* Fetch parliamentary questions feed from MCP.
|
|
1565
|
-
*
|
|
1560
|
+
* Fixed-window feed; `timeframe` is ignored by the server.
|
|
1566
1561
|
*
|
|
1567
1562
|
* @param client - MCP client or null
|
|
1568
|
-
* @param
|
|
1563
|
+
* @param _timeframe - Retained for signature compatibility (ignored by the server)
|
|
1569
1564
|
* @returns Array of question feed items
|
|
1570
1565
|
*/
|
|
1571
|
-
export async function fetchQuestionsFeed(client,
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
while (currentTimeframe) {
|
|
1576
|
-
const tf = currentTimeframe;
|
|
1577
|
-
try {
|
|
1578
|
-
console.log(`${MCP_FETCH_PREFIX} Fetching parliamentary questions feed (${currentTimeframe})...`);
|
|
1579
|
-
const result = await callMCP(() => client.getParliamentaryQuestionsFeed({ timeframe: tf, limit: 20 }), undefined, 'get_parliamentary_questions_feed');
|
|
1580
|
-
const items = parseFeedResult(result).map((item) => mapFeedItemBase(item));
|
|
1581
|
-
if (items.length > 0 || !getWiderTimeframe(currentTimeframe))
|
|
1582
|
-
return items;
|
|
1583
|
-
console.log(`${INFO_PREFIX} questions feed empty for ${currentTimeframe}, widening timeframe...`);
|
|
1584
|
-
currentTimeframe = getWiderTimeframe(currentTimeframe);
|
|
1585
|
-
}
|
|
1586
|
-
catch (error) {
|
|
1587
|
-
const wider = handleFeedFetchError(error, tf, 'get_parliamentary_questions_feed');
|
|
1588
|
-
if (wider) {
|
|
1589
|
-
currentTimeframe = wider;
|
|
1590
|
-
}
|
|
1591
|
-
else {
|
|
1592
|
-
return [];
|
|
1593
|
-
}
|
|
1594
|
-
}
|
|
1595
|
-
}
|
|
1596
|
-
return [];
|
|
1566
|
+
export async function fetchQuestionsFeed(client,
|
|
1567
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1568
|
+
_timeframe = 'one-week') {
|
|
1569
|
+
return fetchFixedWindowFeed(client, 'get_parliamentary_questions_feed', () => client.getParliamentaryQuestionsFeed({ limit: 20 }));
|
|
1597
1570
|
}
|
|
1598
1571
|
/**
|
|
1599
1572
|
* Fetch MEP declarations feed from MCP.
|
|
@@ -1611,7 +1584,7 @@ export async function fetchDeclarationsFeed(client, timeframe = 'one-week') {
|
|
|
1611
1584
|
return parseFeedResult(result).map((item) => mapFeedItemBase(item));
|
|
1612
1585
|
}
|
|
1613
1586
|
catch (error) {
|
|
1614
|
-
if (error
|
|
1587
|
+
if (isStopRetryError(error))
|
|
1615
1588
|
return [];
|
|
1616
1589
|
const message = error instanceof Error ? error.message : String(error);
|
|
1617
1590
|
console.warn(`${WARN_PREFIX} get_mep_declarations_feed failed:`, message);
|
|
@@ -1621,20 +1594,28 @@ export async function fetchDeclarationsFeed(client, timeframe = 'one-week') {
|
|
|
1621
1594
|
/**
|
|
1622
1595
|
* Fetch corporate bodies feed from MCP.
|
|
1623
1596
|
*
|
|
1597
|
+
* `_timeframe` is retained only for signature compatibility with sliding-window
|
|
1598
|
+
* fetchers (so the shared `fetchEPFeedData` orchestrator can dispatch uniformly);
|
|
1599
|
+
* the EP MCP server serves a server-defined fixed window for this feed and
|
|
1600
|
+
* ignores any timeframe input (as of v1.2.10; pre-v1.2.10 it rejected with
|
|
1601
|
+
* `INVALID_PARAMS` — see Hack23/European-Parliament-MCP-Server#377).
|
|
1602
|
+
*
|
|
1624
1603
|
* @param client - MCP client or null
|
|
1625
|
-
* @param
|
|
1604
|
+
* @param _timeframe - Ignored by the server; kept for signature compatibility
|
|
1626
1605
|
* @returns Array of corporate body feed items
|
|
1627
1606
|
*/
|
|
1628
|
-
export async function fetchCorporateBodiesFeed(client,
|
|
1607
|
+
export async function fetchCorporateBodiesFeed(client,
|
|
1608
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1609
|
+
_timeframe = 'one-week') {
|
|
1629
1610
|
if (!client)
|
|
1630
1611
|
return [];
|
|
1631
1612
|
try {
|
|
1632
|
-
console.log(`${MCP_FETCH_PREFIX} Fetching corporate bodies feed (
|
|
1633
|
-
const result = await callMCP(() => client.getCorporateBodiesFeed({
|
|
1613
|
+
console.log(`${MCP_FETCH_PREFIX} Fetching corporate bodies feed (fixed window)...`);
|
|
1614
|
+
const result = await callMCP(() => client.getCorporateBodiesFeed({ limit: 20 }), undefined, 'get_corporate_bodies_feed');
|
|
1634
1615
|
return parseFeedResult(result).map((item) => mapFeedItemBase(item));
|
|
1635
1616
|
}
|
|
1636
1617
|
catch (error) {
|
|
1637
|
-
if (error
|
|
1618
|
+
if (isStopRetryError(error))
|
|
1638
1619
|
return [];
|
|
1639
1620
|
const message = error instanceof Error ? error.message : String(error);
|
|
1640
1621
|
console.warn(`${WARN_PREFIX} get_corporate_bodies_feed failed:`, message);
|
package/scripts/index.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export * from './types/index.js';
|
|
|
37
37
|
export { MCPConnection, MCPSessionExpiredError, MCPRateLimitError, isRetriableError, formatRetryAfter, parseSSEResponse, } from './mcp/mcp-connection.js';
|
|
38
38
|
export { EuropeanParliamentMCPClient, getEPMCPClient, closeEPMCPClient, } from './mcp/ep-mcp-client.js';
|
|
39
39
|
export { WorldBankMCPClient, getWBMCPClient, closeWBMCPClient } from './mcp/wb-mcp-client.js';
|
|
40
|
+
export { IMFMCPClient, IMF_MCP_TOOLS, getIMFMCPClient, closeIMFMCPClient, } from './mcp/imf-mcp-client.js';
|
|
40
41
|
export { type CircuitState, type CircuitBreakerOptions, CircuitBreaker, type MCPRetryPolicy, withRetry, } from './mcp/mcp-retry.js';
|
|
41
42
|
export { type ToolHealthEntry, type HealthSnapshot, MCPHealthMonitor } from './mcp/mcp-health.js';
|
|
42
43
|
export { scoreVotingAnomaly, analyzeCoalitionCohesion, scoreMEPInfluence, calculateLegislativeVelocity, rankBySignificance, buildIntelligenceSection, buildDefaultStakeholderPerspectives, scoreStakeholderInfluence, buildStakeholderOutcomeMatrix, rankStakeholdersByInfluence, computeVotingIntensity, detectCoalitionShifts, computePolarizationIndex, detectVotingTrends, computeCrossSessionCoalitionStability, rankMEPInfluenceByTopic, buildLegislativeVelocityReport, } from './utils/intelligence-analysis.js';
|
|
@@ -45,6 +46,7 @@ export { assessAnalysisDepth, assessStakeholderCoverage, assessVisualizationQual
|
|
|
45
46
|
export { scoreSignificance, scoreBatch, clampScore, deriveDecision, formatScoreMarkdown, formatBatchMarkdown, WEIGHT_PARLIAMENTARY, WEIGHT_POLICY, WEIGHT_PUBLIC_INTEREST, WEIGHT_URGENCY, WEIGHT_INSTITUTIONAL, THRESHOLD_PUBLISH, THRESHOLD_HOLD, } from './utils/significance-scoring.js';
|
|
46
47
|
export { parseFrontmatter, aggregateSWOT, aggregateRisks, extractSummaryLine, aggregateConfidence, findMarkdownFiles, generateEditorialRecommendations, buildSynthesisSummary, formatSynthesisMarkdown, } from './generators/synthesis-summary.js';
|
|
47
48
|
export { validateArticleContent, validateTranslationCompleteness, } from './utils/content-validator.js';
|
|
49
|
+
export { WORLD_BANK_STRONG_FINGERPRINTS, WORLD_BANK_INDICATOR_CODES, WORLD_BANK_FINGERPRINTS, hasWorldBankEvidence, articlePolicyHasWorldBank, IMF_STRONG_FINGERPRINTS, IMF_INDICATOR_CODES, hasIMFEvidence, articlePolicyHasEconomicContext, } from './utils/content-validator.js';
|
|
48
50
|
export { enrichMetadataFromContent } from './utils/content-metadata.js';
|
|
49
51
|
export { buildMetadataDatabase, writeMetadataDatabase, readMetadataDatabase, updateMetadataDatabase, updateIntelligenceIndex, } from './utils/news-metadata.js';
|
|
50
52
|
export { pl, pl as pluralizeCount } from './utils/metadata-utils.js';
|
|
@@ -53,6 +55,7 @@ export { stripHtmlTags, stripScriptBlocks } from './utils/html-sanitize.js';
|
|
|
53
55
|
export { parseArticleFilename, formatSlug, calculateReadTime, escapeHTML, isSafeURL, validateArticleHTML, type ArticleValidationResult, } from './utils/file-utils.js';
|
|
54
56
|
export { detectCategory } from './utils/article-category.js';
|
|
55
57
|
export { EU_COUNTRY_CODES, EU_AGGREGATE_CODE, COMPARISON_COUNTRIES, WB_AGGREGATE_LABELS, POLICY_INDICATORS, parseWorldBankCSV, formatIndicatorValue, getMostRecentValue, buildEconomicContext, getWorldBankCountryCode, isEUMemberState, buildEconomicContextHTML, } from './utils/world-bank-data.js';
|
|
58
|
+
export { IMF_EU_COUNTRY_CODES, IMF_COUNTRY_CODE_OVERRIDES, IMF_EURO_AREA_CODE, IMF_AGGREGATE_LABELS, IMF_POLICY_INDICATORS, IMF_INDICATOR_SDMX_CODES, getIMFCountryCode, isIMFEUMemberState, parseSDMXJSON, getMostRecentObservation, getForecastPoints, formatIMFValue, buildIMFEconomicContext, buildIMFEconomicContextHTML, } from './utils/imf-data.js';
|
|
56
59
|
export { generateArticleHTML } from './templates/article-template.js';
|
|
57
60
|
export { computeArticleQualityScore, buildTableOfContents, buildQualityScoreBadge, } from './templates/section-builders.js';
|
|
58
61
|
export { ALL_LANGUAGES, LANGUAGE_PRESETS, LANGUAGE_FLAGS, LANGUAGE_NAMES, getLocalizedString, isSupportedLanguage, getTextDirection, } from './constants/language-core.js';
|
package/scripts/index.js
CHANGED
|
@@ -41,6 +41,7 @@ export * from './types/index.js';
|
|
|
41
41
|
export { MCPConnection, MCPSessionExpiredError, MCPRateLimitError, isRetriableError, formatRetryAfter, parseSSEResponse, } from './mcp/mcp-connection.js';
|
|
42
42
|
export { EuropeanParliamentMCPClient, getEPMCPClient, closeEPMCPClient, } from './mcp/ep-mcp-client.js';
|
|
43
43
|
export { WorldBankMCPClient, getWBMCPClient, closeWBMCPClient } from './mcp/wb-mcp-client.js';
|
|
44
|
+
export { IMFMCPClient, IMF_MCP_TOOLS, getIMFMCPClient, closeIMFMCPClient, } from './mcp/imf-mcp-client.js';
|
|
44
45
|
export { CircuitBreaker, withRetry, } from './mcp/mcp-retry.js';
|
|
45
46
|
export { MCPHealthMonitor } from './mcp/mcp-health.js';
|
|
46
47
|
// ─── Intelligence Analysis ───────────────────────────────────────────────────
|
|
@@ -55,6 +56,8 @@ export { scoreSignificance, scoreBatch, clampScore, deriveDecision, formatScoreM
|
|
|
55
56
|
export { parseFrontmatter, aggregateSWOT, aggregateRisks, extractSummaryLine, aggregateConfidence, findMarkdownFiles, generateEditorialRecommendations, buildSynthesisSummary, formatSynthesisMarkdown, } from './generators/synthesis-summary.js';
|
|
56
57
|
// ─── Content Validation ──────────────────────────────────────────────────────
|
|
57
58
|
export { validateArticleContent, validateTranslationCompleteness, } from './utils/content-validator.js';
|
|
59
|
+
// ─── Economic-context evidence helpers (Wave 1 dual-source) ──────────────────
|
|
60
|
+
export { WORLD_BANK_STRONG_FINGERPRINTS, WORLD_BANK_INDICATOR_CODES, WORLD_BANK_FINGERPRINTS, hasWorldBankEvidence, articlePolicyHasWorldBank, IMF_STRONG_FINGERPRINTS, IMF_INDICATOR_CODES, hasIMFEvidence, articlePolicyHasEconomicContext, } from './utils/content-validator.js';
|
|
58
61
|
// ─── Content Metadata ────────────────────────────────────────────────────────
|
|
59
62
|
export { enrichMetadataFromContent } from './utils/content-metadata.js';
|
|
60
63
|
// ─── News Metadata ───────────────────────────────────────────────────────────
|
|
@@ -70,6 +73,8 @@ export { parseArticleFilename, formatSlug, calculateReadTime, escapeHTML, isSafe
|
|
|
70
73
|
export { detectCategory } from './utils/article-category.js';
|
|
71
74
|
// ─── World Bank Data Utilities ───────────────────────────────────────────────
|
|
72
75
|
export { EU_COUNTRY_CODES, EU_AGGREGATE_CODE, COMPARISON_COUNTRIES, WB_AGGREGATE_LABELS, POLICY_INDICATORS, parseWorldBankCSV, formatIndicatorValue, getMostRecentValue, buildEconomicContext, getWorldBankCountryCode, isEUMemberState, buildEconomicContextHTML, } from './utils/world-bank-data.js';
|
|
76
|
+
// ─── IMF Data Utilities ──────────────────────────────────────────────────────
|
|
77
|
+
export { IMF_EU_COUNTRY_CODES, IMF_COUNTRY_CODE_OVERRIDES, IMF_EURO_AREA_CODE, IMF_AGGREGATE_LABELS, IMF_POLICY_INDICATORS, IMF_INDICATOR_SDMX_CODES, getIMFCountryCode, isIMFEUMemberState, parseSDMXJSON, getMostRecentObservation, getForecastPoints, formatIMFValue, buildIMFEconomicContext, buildIMFEconomicContextHTML, } from './utils/imf-data.js';
|
|
73
78
|
// ─── Templates ───────────────────────────────────────────────────────────────
|
|
74
79
|
export { generateArticleHTML } from './templates/article-template.js';
|
|
75
80
|
export { computeArticleQualityScore, buildTableOfContents, buildQualityScoreBadge, } from './templates/section-builders.js';
|