euparliamentmonitor 0.8.24 → 0.8.26
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/package.json +2 -2
- package/scripts/constants/committee-indicator-map.d.ts +19 -0
- package/scripts/constants/committee-indicator-map.js +19 -0
- package/scripts/index.d.ts +1 -1
- package/scripts/index.js +1 -1
- package/scripts/mcp/ep-mcp-client.d.ts +15 -0
- package/scripts/mcp/ep-mcp-client.js +53 -14
- package/scripts/mcp/mcp-connection.js +11 -4
- package/scripts/types/mcp.d.ts +2 -0
- package/scripts/types/world-bank.d.ts +67 -2
- package/scripts/utils/world-bank-data.d.ts +33 -1
- package/scripts/utils/world-bank-data.js +108 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "euparliamentmonitor",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.26",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "European Parliament Intelligence Platform - Monitor political activity with systematic transparency",
|
|
6
6
|
"main": "scripts/index.js",
|
|
@@ -170,7 +170,7 @@
|
|
|
170
170
|
"node": ">=25"
|
|
171
171
|
},
|
|
172
172
|
"dependencies": {
|
|
173
|
-
"european-parliament-mcp-server": "1.2.
|
|
173
|
+
"european-parliament-mcp-server": "1.2.2"
|
|
174
174
|
},
|
|
175
175
|
"optionalDependencies": {
|
|
176
176
|
"worldbank-mcp": "1.0.1"
|
|
@@ -10,12 +10,31 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Used by news generation strategies to automatically select the right
|
|
12
12
|
* economic indicators when enriching articles with World Bank data.
|
|
13
|
+
*
|
|
14
|
+
* ## ⚠️ For AI Agents / Agentic Workflows
|
|
15
|
+
*
|
|
16
|
+
* The 34 indicators in {@link WB_INDICATORS} are a **curated subset** mapped
|
|
17
|
+
* to EP committee mandates. The full World Bank catalog has **thousands** of
|
|
18
|
+
* indicators. For dynamic indicator discovery:
|
|
19
|
+
*
|
|
20
|
+
* 1. Use `search-indicators` MCP tool to find indicators by keyword on demand
|
|
21
|
+
* 2. Read `analysis/worldbank/indicator-catalog.md` for the full **200+ indicator**
|
|
22
|
+
* reference organized by 10 EP policy domains
|
|
23
|
+
* 3. Use `analysis/worldbank/use-cases.md` to decide when indicators add editorial value
|
|
24
|
+
* 4. Use `analysis/worldbank/chart-integration-guide.md` for visualization templates
|
|
25
|
+
*
|
|
26
|
+
* **Never assume the indicators below are exhaustive.** Always consider whether
|
|
27
|
+
* `search-indicators` would reveal a more specific indicator for the policy topic.
|
|
13
28
|
*/
|
|
14
29
|
import { ArticleCategory, AnalysisPerspective } from '../types/common.js';
|
|
15
30
|
/**
|
|
16
31
|
* Extended set of World Bank indicator IDs relevant to EU Parliament policy areas.
|
|
17
32
|
* Superset of {@link PolicyRelevantIndicators} — includes domain-specific indicators
|
|
18
33
|
* that map to individual committee mandates.
|
|
34
|
+
*
|
|
35
|
+
* ⚠️ **AI Agents**: This is a **curated subset of 34 indicators**. The World Bank
|
|
36
|
+
* has thousands more. Use `search-indicators` MCP tool for on-demand discovery.
|
|
37
|
+
* Full reference: `analysis/worldbank/indicator-catalog.md` (200+ indicators).
|
|
19
38
|
*/
|
|
20
39
|
export declare const WB_INDICATORS: {
|
|
21
40
|
/** GDP (current US$) */
|
|
@@ -12,6 +12,21 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Used by news generation strategies to automatically select the right
|
|
14
14
|
* economic indicators when enriching articles with World Bank data.
|
|
15
|
+
*
|
|
16
|
+
* ## ⚠️ For AI Agents / Agentic Workflows
|
|
17
|
+
*
|
|
18
|
+
* The 34 indicators in {@link WB_INDICATORS} are a **curated subset** mapped
|
|
19
|
+
* to EP committee mandates. The full World Bank catalog has **thousands** of
|
|
20
|
+
* indicators. For dynamic indicator discovery:
|
|
21
|
+
*
|
|
22
|
+
* 1. Use `search-indicators` MCP tool to find indicators by keyword on demand
|
|
23
|
+
* 2. Read `analysis/worldbank/indicator-catalog.md` for the full **200+ indicator**
|
|
24
|
+
* reference organized by 10 EP policy domains
|
|
25
|
+
* 3. Use `analysis/worldbank/use-cases.md` to decide when indicators add editorial value
|
|
26
|
+
* 4. Use `analysis/worldbank/chart-integration-guide.md` for visualization templates
|
|
27
|
+
*
|
|
28
|
+
* **Never assume the indicators below are exhaustive.** Always consider whether
|
|
29
|
+
* `search-indicators` would reveal a more specific indicator for the policy topic.
|
|
15
30
|
*/
|
|
16
31
|
import { ArticleCategory, AnalysisPerspective } from '../types/common.js';
|
|
17
32
|
// ─── Priority Constants ──────────────────────────────────────────────────────
|
|
@@ -61,6 +76,10 @@ const N = {
|
|
|
61
76
|
* Extended set of World Bank indicator IDs relevant to EU Parliament policy areas.
|
|
62
77
|
* Superset of {@link PolicyRelevantIndicators} — includes domain-specific indicators
|
|
63
78
|
* that map to individual committee mandates.
|
|
79
|
+
*
|
|
80
|
+
* ⚠️ **AI Agents**: This is a **curated subset of 34 indicators**. The World Bank
|
|
81
|
+
* has thousands more. Use `search-indicators` MCP tool for on-demand discovery.
|
|
82
|
+
* Full reference: `analysis/worldbank/indicator-catalog.md` (200+ indicators).
|
|
64
83
|
*/
|
|
65
84
|
export const WB_INDICATORS = {
|
|
66
85
|
// ── Macro-economic ──
|
package/scripts/index.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ export { assessPoliticalThreats, buildActorThreatProfiles, buildConsequenceTree,
|
|
|
44
44
|
export { stripHtmlTags, stripScriptBlocks } from './utils/html-sanitize.js';
|
|
45
45
|
export { parseArticleFilename, formatSlug, calculateReadTime, escapeHTML, isSafeURL, validateArticleHTML, type ArticleValidationResult, } from './utils/file-utils.js';
|
|
46
46
|
export { detectCategory } from './utils/article-category.js';
|
|
47
|
-
export { EU_COUNTRY_CODES, EU_AGGREGATE_CODE, POLICY_INDICATORS, parseWorldBankCSV, formatIndicatorValue, getMostRecentValue, buildEconomicContext, getWorldBankCountryCode, isEUMemberState, buildEconomicContextHTML, } from './utils/world-bank-data.js';
|
|
47
|
+
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';
|
|
48
48
|
export { generateArticleHTML } from './templates/article-template.js';
|
|
49
49
|
export { computeArticleQualityScore, buildTableOfContents, buildQualityScoreBadge, } from './templates/section-builders.js';
|
|
50
50
|
export { ALL_LANGUAGES, LANGUAGE_PRESETS, LANGUAGE_FLAGS, LANGUAGE_NAMES, getLocalizedString, isSupportedLanguage, getTextDirection, } from './constants/language-core.js';
|
package/scripts/index.js
CHANGED
|
@@ -61,7 +61,7 @@ export { parseArticleFilename, formatSlug, calculateReadTime, escapeHTML, isSafe
|
|
|
61
61
|
// ─── Article Category Detection ──────────────────────────────────────────────
|
|
62
62
|
export { detectCategory } from './utils/article-category.js';
|
|
63
63
|
// ─── World Bank Data Utilities ───────────────────────────────────────────────
|
|
64
|
-
export { EU_COUNTRY_CODES, EU_AGGREGATE_CODE, POLICY_INDICATORS, parseWorldBankCSV, formatIndicatorValue, getMostRecentValue, buildEconomicContext, getWorldBankCountryCode, isEUMemberState, buildEconomicContextHTML, } from './utils/world-bank-data.js';
|
|
64
|
+
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';
|
|
65
65
|
// ─── Templates ───────────────────────────────────────────────────────────────
|
|
66
66
|
export { generateArticleHTML } from './templates/article-template.js';
|
|
67
67
|
export { computeArticleQualityScore, buildTableOfContents, buildQualityScoreBadge, } from './templates/section-builders.js';
|
|
@@ -14,6 +14,15 @@ export declare class EuropeanParliamentMCPClient extends MCPConnection {
|
|
|
14
14
|
private readonly _failedTools;
|
|
15
15
|
/** Tracks tools that have been called (attempted) in the current session */
|
|
16
16
|
private readonly _calledTools;
|
|
17
|
+
/**
|
|
18
|
+
* Record a tool failure and log a warning.
|
|
19
|
+
*
|
|
20
|
+
* @param toolName - MCP tool name that failed
|
|
21
|
+
* @param errorText - Raw error text from the failure
|
|
22
|
+
* @param fallbackText - JSON text for the fallback result
|
|
23
|
+
* @returns Fallback MCPToolResult
|
|
24
|
+
*/
|
|
25
|
+
private _recordToolFailure;
|
|
17
26
|
/**
|
|
18
27
|
* Generic error-safe wrapper around {@link callToolWithRetry}.
|
|
19
28
|
* Retries transient failures (timeouts, connection drops) with a bounded
|
|
@@ -22,6 +31,12 @@ export declare class EuropeanParliamentMCPClient extends MCPConnection {
|
|
|
22
31
|
* Catches any error thrown by the tool (or by the args factory), logs a warning,
|
|
23
32
|
* and returns a fallback payload.
|
|
24
33
|
*
|
|
34
|
+
* Also inspects the tool result for the MCP protocol `isError` flag. When
|
|
35
|
+
* `isError === true`, the first content item's text is passed through
|
|
36
|
+
* {@link classifyToolError} for diagnostic categorization, and the tool is
|
|
37
|
+
* recorded as failed via {@link _recordToolFailure}. This handles EP MCP
|
|
38
|
+
* Server error responses that are returned (not thrown) as structured results.
|
|
39
|
+
*
|
|
25
40
|
* Accepts either a plain args object or a factory function `() => object`.
|
|
26
41
|
* Using a factory ensures that options normalization/destructuring runs inside
|
|
27
42
|
* the try/catch so invalid runtime inputs fall back gracefully.
|
|
@@ -27,21 +27,36 @@ const PROCEDURE_EVENT_FALLBACK = '{"event": null}';
|
|
|
27
27
|
/** Fallback payload for server health status */
|
|
28
28
|
const SERVER_HEALTH_FALLBACK = '{"server": null, "feeds": []}';
|
|
29
29
|
/**
|
|
30
|
-
* Classify an error message into a diagnostic error category
|
|
31
|
-
* EP MCP Server v1.2.1 standardized error categories.
|
|
30
|
+
* Classify an error message into a diagnostic error category.
|
|
32
31
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
32
|
+
* Maps EP MCP Server v1.2.2 structured error codes and generic HTTP/network
|
|
33
|
+
* errors into one of six broad categories used for logging and retry decisions:
|
|
34
|
+
*
|
|
35
|
+
* Returned categories (priority order):
|
|
36
|
+
* 1. `INTERNAL_ERROR` — EP MCP `INTERNAL_ERROR` (catch-all for DNS, TLS, unclassified upstream failures)
|
|
37
|
+
* 2. `SERVER_ERROR` — EP MCP `UPSTREAM_500`/`UPSTREAM_503`/`SERVER_ERROR`, or gateway 5xx patterns
|
|
38
|
+
* 3. `TIMEOUT` — EP MCP `UPSTREAM_TIMEOUT`, or generic "timeout" strings
|
|
39
|
+
* 4. `RATE_LIMIT` — EP MCP `RATE_LIMITED`, HTTP 429, or "rate limit"/"too many requests" strings
|
|
40
|
+
* 5. `NOT_FOUND` — EP MCP `UPSTREAM_404`, or generic "404" strings
|
|
41
|
+
* 6. `UNKNOWN` — everything else
|
|
39
42
|
*
|
|
40
43
|
* @param message - Raw error message
|
|
41
44
|
* @returns Diagnostic error category string
|
|
42
45
|
*/
|
|
43
46
|
function classifyToolError(message) {
|
|
44
47
|
const lowerMsg = message.toLowerCase();
|
|
48
|
+
// EP MCP Server v1.2.2 structured error codes (matched case-insensitively)
|
|
49
|
+
if (lowerMsg.includes('internal_error')) {
|
|
50
|
+
return 'INTERNAL_ERROR';
|
|
51
|
+
}
|
|
52
|
+
if (lowerMsg.includes('upstream_500') ||
|
|
53
|
+
lowerMsg.includes('upstream_503') ||
|
|
54
|
+
lowerMsg.includes('server_error')) {
|
|
55
|
+
return 'SERVER_ERROR';
|
|
56
|
+
}
|
|
57
|
+
if (lowerMsg.includes('upstream_timeout')) {
|
|
58
|
+
return 'TIMEOUT';
|
|
59
|
+
}
|
|
45
60
|
if (lowerMsg.includes('gateway timeout') ||
|
|
46
61
|
lowerMsg.includes('gateway error 500') ||
|
|
47
62
|
lowerMsg.includes('gateway error 502') ||
|
|
@@ -51,10 +66,11 @@ function classifyToolError(message) {
|
|
|
51
66
|
}
|
|
52
67
|
if (lowerMsg.includes('429') ||
|
|
53
68
|
lowerMsg.includes('rate limit') ||
|
|
54
|
-
lowerMsg.includes('too many requests')
|
|
69
|
+
lowerMsg.includes('too many requests') ||
|
|
70
|
+
lowerMsg.includes('rate_limited')) {
|
|
55
71
|
return 'RATE_LIMIT';
|
|
56
72
|
}
|
|
57
|
-
if (lowerMsg.includes('404'))
|
|
73
|
+
if (lowerMsg.includes('404') || lowerMsg.includes('upstream_404'))
|
|
58
74
|
return 'NOT_FOUND';
|
|
59
75
|
if (lowerMsg.includes('timeout'))
|
|
60
76
|
return 'TIMEOUT';
|
|
@@ -69,6 +85,20 @@ export class EuropeanParliamentMCPClient extends MCPConnection {
|
|
|
69
85
|
_failedTools = new Map();
|
|
70
86
|
/** Tracks tools that have been called (attempted) in the current session */
|
|
71
87
|
_calledTools = new Set();
|
|
88
|
+
/**
|
|
89
|
+
* Record a tool failure and log a warning.
|
|
90
|
+
*
|
|
91
|
+
* @param toolName - MCP tool name that failed
|
|
92
|
+
* @param errorText - Raw error text from the failure
|
|
93
|
+
* @param fallbackText - JSON text for the fallback result
|
|
94
|
+
* @returns Fallback MCPToolResult
|
|
95
|
+
*/
|
|
96
|
+
_recordToolFailure(toolName, errorText, fallbackText) {
|
|
97
|
+
const errorType = classifyToolError(errorText);
|
|
98
|
+
this._failedTools.set(toolName, `${errorType}: ${errorText.slice(0, 200)}`);
|
|
99
|
+
console.warn(`⚠️ ${toolName} failed [${errorType}]:`, errorText.slice(0, 200));
|
|
100
|
+
return { content: [{ type: 'text', text: fallbackText }] };
|
|
101
|
+
}
|
|
72
102
|
/**
|
|
73
103
|
* Generic error-safe wrapper around {@link callToolWithRetry}.
|
|
74
104
|
* Retries transient failures (timeouts, connection drops) with a bounded
|
|
@@ -77,6 +107,12 @@ export class EuropeanParliamentMCPClient extends MCPConnection {
|
|
|
77
107
|
* Catches any error thrown by the tool (or by the args factory), logs a warning,
|
|
78
108
|
* and returns a fallback payload.
|
|
79
109
|
*
|
|
110
|
+
* Also inspects the tool result for the MCP protocol `isError` flag. When
|
|
111
|
+
* `isError === true`, the first content item's text is passed through
|
|
112
|
+
* {@link classifyToolError} for diagnostic categorization, and the tool is
|
|
113
|
+
* recorded as failed via {@link _recordToolFailure}. This handles EP MCP
|
|
114
|
+
* Server error responses that are returned (not thrown) as structured results.
|
|
115
|
+
*
|
|
80
116
|
* Accepts either a plain args object or a factory function `() => object`.
|
|
81
117
|
* Using a factory ensures that options normalization/destructuring runs inside
|
|
82
118
|
* the try/catch so invalid runtime inputs fall back gracefully.
|
|
@@ -91,16 +127,19 @@ export class EuropeanParliamentMCPClient extends MCPConnection {
|
|
|
91
127
|
try {
|
|
92
128
|
const resolvedArgs = typeof args === 'function' ? args() : args;
|
|
93
129
|
const result = await this.callToolWithRetry(toolName, resolvedArgs);
|
|
130
|
+
// Inspect the result for structured error responses from the EP MCP server.
|
|
131
|
+
// The server may return isError: true with JSON content containing errorCode
|
|
132
|
+
// (e.g., INTERNAL_ERROR, UPSTREAM_500) instead of throwing an exception.
|
|
133
|
+
if (result.isError === true) {
|
|
134
|
+
return this._recordToolFailure(toolName, result.content?.[0]?.text ?? '', fallbackText);
|
|
135
|
+
}
|
|
94
136
|
// Clear from failed tools on success
|
|
95
137
|
this._failedTools.delete(toolName);
|
|
96
138
|
return result;
|
|
97
139
|
}
|
|
98
140
|
catch (error) {
|
|
99
141
|
const message = error instanceof Error ? error.message : String(error);
|
|
100
|
-
|
|
101
|
-
this._failedTools.set(toolName, `${errorType}: ${message}`);
|
|
102
|
-
console.warn(`⚠️ ${toolName} failed [${errorType}]:`, message);
|
|
103
|
-
return { content: [{ type: 'text', text: fallbackText }] };
|
|
142
|
+
return this._recordToolFailure(toolName, message, fallbackText);
|
|
104
143
|
}
|
|
105
144
|
}
|
|
106
145
|
/**
|
|
@@ -483,11 +483,18 @@ export class MCPConnection {
|
|
|
483
483
|
const command = isJavaScriptFile ? process.execPath : this.serverPath;
|
|
484
484
|
const args = isJavaScriptFile ? [this.serverPath] : [];
|
|
485
485
|
// Ensure EP_REQUEST_TIMEOUT_MS is propagated to the MCP server subprocess.
|
|
486
|
-
// The EP MCP server defaults to only 10 seconds
|
|
487
|
-
// slow EP API feed endpoints (events, procedures, documents, etc.).
|
|
486
|
+
// The EP MCP server defaults to only 10 seconds (v1.1.x) or 60 seconds (v1.2.x);
|
|
487
|
+
// we need 90+ seconds for slow EP API feed endpoints (events, procedures, documents, etc.).
|
|
488
488
|
const childEnv = { ...process.env };
|
|
489
|
-
|
|
490
|
-
childEnv['EP_REQUEST_TIMEOUT_MS']
|
|
489
|
+
const effectiveTimeoutMs = childEnv['EP_REQUEST_TIMEOUT_MS']
|
|
490
|
+
? Number(childEnv['EP_REQUEST_TIMEOUT_MS'])
|
|
491
|
+
: REQUEST_TIMEOUT_MS;
|
|
492
|
+
childEnv['EP_REQUEST_TIMEOUT_MS'] = String(effectiveTimeoutMs);
|
|
493
|
+
// Pass --timeout as CLI arg (highest precedence in EP MCP server).
|
|
494
|
+
// This guarantees the timeout is applied even when the env var is not
|
|
495
|
+
// read at module load time (e.g. due to import ordering in some versions).
|
|
496
|
+
if (!isJavaScriptFile) {
|
|
497
|
+
args.push('--timeout', String(effectiveTimeoutMs));
|
|
491
498
|
}
|
|
492
499
|
this.process = spawn(command, args, {
|
|
493
500
|
stdio: ['pipe', 'pipe', 'pipe'],
|
package/scripts/types/mcp.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export interface MCPContentItem {
|
|
|
25
25
|
/** MCP tool call result */
|
|
26
26
|
export interface MCPToolResult {
|
|
27
27
|
content?: MCPContentItem[] | undefined;
|
|
28
|
+
/** Set to `true` by the MCP server when the tool invocation produced an error response */
|
|
29
|
+
isError?: boolean | undefined;
|
|
28
30
|
}
|
|
29
31
|
/** JSON-RPC 2.0 request */
|
|
30
32
|
export interface JSONRPCRequest {
|
|
@@ -69,17 +69,82 @@ export interface PolicyRelevantIndicators {
|
|
|
69
69
|
gdp: string;
|
|
70
70
|
/** GDP growth (annual %) — NY.GDP.MKTP.KD.ZG */
|
|
71
71
|
gdpGrowth: string;
|
|
72
|
+
/** GDP per capita (current US$) — NY.GDP.PCAP.CD */
|
|
73
|
+
gdpPerCapita: string;
|
|
74
|
+
/** GNI per capita, Atlas method (current US$) — NY.GNP.PCAP.CD */
|
|
75
|
+
gniPerCapita: string;
|
|
72
76
|
/** Inflation, consumer prices (annual %) — FP.CPI.TOTL.ZG */
|
|
73
77
|
inflation: string;
|
|
74
78
|
/** Unemployment, total (% of total labor force) — SL.UEM.TOTL.ZS */
|
|
75
79
|
unemployment: string;
|
|
80
|
+
/** Exports of goods and services (% of GDP) — NE.EXP.GNFS.ZS */
|
|
81
|
+
exportsGdp: string;
|
|
82
|
+
/** Foreign direct investment, net inflows (BoP, current US$) — BN.KLT.DINV.CD */
|
|
83
|
+
fdiNet: string;
|
|
76
84
|
/** Trade (% of GDP) — NE.TRD.GNFS.ZS */
|
|
77
85
|
trade: string;
|
|
78
|
-
/**
|
|
79
|
-
|
|
86
|
+
/** Tax revenue (% of GDP) — GC.TAX.TOTL.GD.ZS */
|
|
87
|
+
taxRevenue: string;
|
|
88
|
+
/** General government final consumption expenditure (% of GDP) — NE.CON.GOVT.ZS */
|
|
89
|
+
govExpenditure: string;
|
|
90
|
+
/** Military expenditure (% of GDP) — MS.MIL.XPND.GD.ZS */
|
|
91
|
+
militaryExpenditure: string;
|
|
80
92
|
/** Population, total — SP.POP.TOTL */
|
|
81
93
|
population: string;
|
|
94
|
+
/** Life expectancy at birth, total (years) — SP.DYN.LE00.IN */
|
|
95
|
+
lifeExpectancy: string;
|
|
96
|
+
/** Birth rate, crude (per 1,000 people) — SP.DYN.CBRT.IN */
|
|
97
|
+
birthRate: string;
|
|
98
|
+
/** Death rate, crude (per 1,000 people) — SP.DYN.CDRT.IN */
|
|
99
|
+
deathRate: string;
|
|
100
|
+
/** Individuals using the Internet (% of population) — IT.NET.USER.ZS */
|
|
101
|
+
internetUsers: string;
|
|
102
|
+
/** Current health expenditure (% of GDP) — SH.XPD.CHEX.GD.ZS */
|
|
103
|
+
healthExpenditure: string;
|
|
104
|
+
/** Physicians (per 1,000 people) — SH.MED.PHYS.ZS */
|
|
105
|
+
physicians: string;
|
|
106
|
+
/** Hospital beds (per 1,000 people) — SH.MED.BEDS.ZS */
|
|
107
|
+
hospitalBeds: string;
|
|
108
|
+
/** Government expenditure on education, total (% of GDP) — SE.XPD.TOTL.GD.ZS */
|
|
109
|
+
educationExpenditure: string;
|
|
110
|
+
/** CO2 emissions (metric tons per capita) — EN.ATM.CO2E.PC */
|
|
111
|
+
co2Emissions: string;
|
|
112
|
+
/** Renewable energy consumption (% of total) — EG.FEC.RNEW.ZS */
|
|
113
|
+
renewableEnergy: string;
|
|
82
114
|
/** Research and development expenditure (% of GDP) — GB.XPD.RSDV.GD.ZS */
|
|
83
115
|
rdExpenditure: string;
|
|
116
|
+
/** High-technology exports (% of manufactured exports) — TX.VAL.TECH.MF.ZS */
|
|
117
|
+
hightechExports: string;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* World Bank MCP tool names available for data fetching.
|
|
121
|
+
* Maps to the tool functions on the worldbank-mcp server.
|
|
122
|
+
*
|
|
123
|
+
* These type literals use **kebab-case** (e.g., `get-economic-data`) to match
|
|
124
|
+
* the underlying tool registration names in worldbank-mcp@1.0.0
|
|
125
|
+
* (`server.tool('get-economic-data', ...)`).
|
|
126
|
+
* When called via the MCP gateway prefix in this repository's workflows, use
|
|
127
|
+
* the corresponding **snake_case** form, for example
|
|
128
|
+
* `world_bank___get_economic_data(...)`.
|
|
129
|
+
*
|
|
130
|
+
* **Note:** The codebase also has a `WorldBankMCPClient.getIndicatorForCountry()`
|
|
131
|
+
* wrapper (in `src/mcp/wb-mcp-client.ts`) that calls the `get_indicator_for_country`
|
|
132
|
+
* tool — this is a legacy convenience method not listed in this type union since it
|
|
133
|
+
* is not part of the standard worldbank-mcp tool surface.
|
|
134
|
+
*/
|
|
135
|
+
export type WBMCPToolName = 'get-economic-data' | 'get-social-data' | 'get-health-data' | 'get-education-data' | 'get-country-info' | 'get-countries' | 'search-indicators';
|
|
136
|
+
/**
|
|
137
|
+
* World Bank MCP tool indicator key mapping.
|
|
138
|
+
* Maps each tool to the indicator key literals it accepts.
|
|
139
|
+
*/
|
|
140
|
+
export interface WBToolIndicatorKeys {
|
|
141
|
+
/** Economic indicators accepted by `get-economic-data` */
|
|
142
|
+
'get-economic-data': 'GDP' | 'GDP_GROWTH' | 'GDP_PER_CAPITA' | 'GNI' | 'GNI_PER_CAPITA' | 'EXPORTS_GDP' | 'FDI_NET' | 'INFLATION' | 'UNEMPLOYMENT';
|
|
143
|
+
/** Social indicators accepted by `get-social-data` */
|
|
144
|
+
'get-social-data': 'POPULATION' | 'LIFE_EXPECTANCY' | 'BIRTH_RATE' | 'DEATH_RATE' | 'INTERNET_USERS';
|
|
145
|
+
/** Health indicators accepted by `get-health-data` */
|
|
146
|
+
'get-health-data': 'HEALTH_EXPENDITURE' | 'PHYSICIANS' | 'HOSPITAL_BEDS' | 'IMMUNIZATION' | 'HIV_PREVALENCE' | 'MALNUTRITION' | 'TUBERCULOSIS';
|
|
147
|
+
/** Education indicators accepted by `get-education-data` */
|
|
148
|
+
'get-education-data': 'LITERACY_RATE' | 'SCHOOL_ENROLLMENT' | 'SCHOOL_COMPLETION' | 'TEACHERS_PRIMARY' | 'EDUCATION_EXPENDITURE';
|
|
84
149
|
}
|
|
85
150
|
//# sourceMappingURL=world-bank.d.ts.map
|
|
@@ -9,6 +9,22 @@
|
|
|
9
9
|
* Functions in this module are designed to be stateless and avoid observable
|
|
10
10
|
* side effects, with the exception of explicitly recording metadata such as
|
|
11
11
|
* data timestamps in returned objects.
|
|
12
|
+
*
|
|
13
|
+
* ## ⚠️ For AI Agents / Agentic Workflows
|
|
14
|
+
*
|
|
15
|
+
* The constants below ({@link POLICY_INDICATORS}, {@link EU_COUNTRY_CODES},
|
|
16
|
+
* {@link COMPARISON_COUNTRIES}) are a **convenience subset** used by TypeScript
|
|
17
|
+
* code for formatting and parsing. They do **NOT** represent the full World Bank
|
|
18
|
+
* indicator inventory.
|
|
19
|
+
*
|
|
20
|
+
* **For indicator selection in articles and analysis:**
|
|
21
|
+
* 1. Read `analysis/worldbank/indicator-catalog.md` — **200+ indicators** by EP policy domain
|
|
22
|
+
* 2. Use `search-indicators` MCP tool to **discover indicators on demand** by keyword
|
|
23
|
+
* 3. Read `analysis/worldbank/eu-country-mapping.md` for country codes + comparison groups
|
|
24
|
+
* 4. Read `analysis/worldbank/chart-integration-guide.md` for Chart.js + Mermaid templates
|
|
25
|
+
*
|
|
26
|
+
* The World Bank MCP server has thousands of indicators beyond the ones listed
|
|
27
|
+
* here. Use `search-indicators` to find the best match for any policy topic.
|
|
12
28
|
*/
|
|
13
29
|
import type { EconomicContext, PolicyRelevantIndicators, WorldBankIndicator } from '../types/world-bank.js';
|
|
14
30
|
/**
|
|
@@ -18,9 +34,25 @@ import type { EconomicContext, PolicyRelevantIndicators, WorldBankIndicator } fr
|
|
|
18
34
|
export declare const EU_COUNTRY_CODES: Readonly<Record<string, string>>;
|
|
19
35
|
/** EU aggregate code in World Bank (European Union) */
|
|
20
36
|
export declare const EU_AGGREGATE_CODE = "EUU";
|
|
37
|
+
/**
|
|
38
|
+
* Comparison country codes for benchmarking EU performance against global peers.
|
|
39
|
+
* Organized by geopolitical relevance to EU Parliament policy analysis.
|
|
40
|
+
*/
|
|
41
|
+
export declare const COMPARISON_COUNTRIES: Readonly<Record<string, string>>;
|
|
42
|
+
/**
|
|
43
|
+
* Aggregate/region codes useful for EU benchmarking.
|
|
44
|
+
* Keys are World Bank group codes; values are human-readable labels.
|
|
45
|
+
*/
|
|
46
|
+
export declare const WB_AGGREGATE_LABELS: Readonly<Record<string, string>>;
|
|
21
47
|
/**
|
|
22
48
|
* World Bank indicator IDs relevant to EU Parliament policy analysis.
|
|
23
|
-
*
|
|
49
|
+
*
|
|
50
|
+
* ⚠️ **AI Agents**: This is a convenience subset of 25 core indicators used by
|
|
51
|
+
* TypeScript formatting code. The World Bank has **thousands** of indicators.
|
|
52
|
+
* For article/analysis generation:
|
|
53
|
+
* - Read `analysis/worldbank/indicator-catalog.md` for the full **200+ indicator** reference
|
|
54
|
+
* - Use `search-indicators` MCP tool to discover indicators on demand by keyword
|
|
55
|
+
* - See `analysis/worldbank/use-cases.md` for when each indicator type adds value
|
|
24
56
|
*/
|
|
25
57
|
export declare const POLICY_INDICATORS: PolicyRelevantIndicators;
|
|
26
58
|
/**
|
|
@@ -37,19 +37,96 @@ export const EU_COUNTRY_CODES = {
|
|
|
37
37
|
};
|
|
38
38
|
/** EU aggregate code in World Bank (European Union) */
|
|
39
39
|
export const EU_AGGREGATE_CODE = 'EUU';
|
|
40
|
+
/**
|
|
41
|
+
* Comparison country codes for benchmarking EU performance against global peers.
|
|
42
|
+
* Organized by geopolitical relevance to EU Parliament policy analysis.
|
|
43
|
+
*/
|
|
44
|
+
export const COMPARISON_COUNTRIES = {
|
|
45
|
+
// ── G7 Non-EU ──
|
|
46
|
+
US: 'USA', // United States
|
|
47
|
+
GB: 'GBR', // United Kingdom (post-Brexit benchmark)
|
|
48
|
+
JP: 'JPN', // Japan
|
|
49
|
+
CA: 'CAN', // Canada
|
|
50
|
+
// ── BRICS ──
|
|
51
|
+
CN: 'CHN', // China
|
|
52
|
+
IN: 'IND', // India
|
|
53
|
+
BR: 'BRA', // Brazil
|
|
54
|
+
RU: 'RUS', // Russia
|
|
55
|
+
ZA: 'ZAF', // South Africa
|
|
56
|
+
// ── EU Candidate States ──
|
|
57
|
+
UA: 'UKR', // Ukraine
|
|
58
|
+
TR: 'TUR', // Türkiye
|
|
59
|
+
RS: 'SRB', // Serbia
|
|
60
|
+
ME: 'MNE', // Montenegro
|
|
61
|
+
AL: 'ALB', // Albania
|
|
62
|
+
MK: 'MKD', // North Macedonia
|
|
63
|
+
MD: 'MDA', // Moldova
|
|
64
|
+
BA: 'BIH', // Bosnia & Herzegovina
|
|
65
|
+
GE: 'GEO', // Georgia
|
|
66
|
+
// ── Key Trade Partners ──
|
|
67
|
+
KR: 'KOR', // South Korea
|
|
68
|
+
AU: 'AUS', // Australia
|
|
69
|
+
NO: 'NOR', // Norway (EEA)
|
|
70
|
+
CH: 'CHE', // Switzerland (EFTA)
|
|
71
|
+
IL: 'ISR', // Israel
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Aggregate/region codes useful for EU benchmarking.
|
|
75
|
+
* Keys are World Bank group codes; values are human-readable labels.
|
|
76
|
+
*/
|
|
77
|
+
export const WB_AGGREGATE_LABELS = {
|
|
78
|
+
EUU: 'European Union',
|
|
79
|
+
EMU: 'Euro area',
|
|
80
|
+
OED: 'OECD members',
|
|
81
|
+
WLD: 'World',
|
|
82
|
+
ECS: 'Europe & Central Asia',
|
|
83
|
+
NAC: 'North America',
|
|
84
|
+
EAS: 'East Asia & Pacific',
|
|
85
|
+
SSF: 'Sub-Saharan Africa',
|
|
86
|
+
};
|
|
40
87
|
/**
|
|
41
88
|
* World Bank indicator IDs relevant to EU Parliament policy analysis.
|
|
42
|
-
*
|
|
89
|
+
*
|
|
90
|
+
* ⚠️ **AI Agents**: This is a convenience subset of 25 core indicators used by
|
|
91
|
+
* TypeScript formatting code. The World Bank has **thousands** of indicators.
|
|
92
|
+
* For article/analysis generation:
|
|
93
|
+
* - Read `analysis/worldbank/indicator-catalog.md` for the full **200+ indicator** reference
|
|
94
|
+
* - Use `search-indicators` MCP tool to discover indicators on demand by keyword
|
|
95
|
+
* - See `analysis/worldbank/use-cases.md` for when each indicator type adds value
|
|
43
96
|
*/
|
|
44
97
|
export const POLICY_INDICATORS = {
|
|
98
|
+
// Macro-economic (get-economic-data)
|
|
45
99
|
gdp: 'NY.GDP.MKTP.CD',
|
|
46
100
|
gdpGrowth: 'NY.GDP.MKTP.KD.ZG',
|
|
101
|
+
gdpPerCapita: 'NY.GDP.PCAP.CD',
|
|
102
|
+
gniPerCapita: 'NY.GNP.PCAP.CD',
|
|
47
103
|
inflation: 'FP.CPI.TOTL.ZG',
|
|
48
104
|
unemployment: 'SL.UEM.TOTL.ZS',
|
|
105
|
+
exportsGdp: 'NE.EXP.GNFS.ZS',
|
|
106
|
+
fdiNet: 'BN.KLT.DINV.CD',
|
|
107
|
+
// Trade & fiscal
|
|
49
108
|
trade: 'NE.TRD.GNFS.ZS',
|
|
50
|
-
|
|
109
|
+
taxRevenue: 'GC.TAX.TOTL.GD.ZS',
|
|
110
|
+
govExpenditure: 'NE.CON.GOVT.ZS',
|
|
111
|
+
militaryExpenditure: 'MS.MIL.XPND.GD.ZS',
|
|
112
|
+
// Social (get-social-data)
|
|
51
113
|
population: 'SP.POP.TOTL',
|
|
114
|
+
lifeExpectancy: 'SP.DYN.LE00.IN',
|
|
115
|
+
birthRate: 'SP.DYN.CBRT.IN',
|
|
116
|
+
deathRate: 'SP.DYN.CDRT.IN',
|
|
117
|
+
internetUsers: 'IT.NET.USER.ZS',
|
|
118
|
+
// Health (get-health-data)
|
|
119
|
+
healthExpenditure: 'SH.XPD.CHEX.GD.ZS',
|
|
120
|
+
physicians: 'SH.MED.PHYS.ZS',
|
|
121
|
+
hospitalBeds: 'SH.MED.BEDS.ZS',
|
|
122
|
+
// Education (get-education-data)
|
|
123
|
+
educationExpenditure: 'SE.XPD.TOTL.GD.ZS',
|
|
124
|
+
// Environment & energy
|
|
125
|
+
co2Emissions: 'EN.ATM.CO2E.PC',
|
|
126
|
+
renewableEnergy: 'EG.FEC.RNEW.ZS',
|
|
127
|
+
// Research & innovation
|
|
52
128
|
rdExpenditure: 'GB.XPD.RSDV.GD.ZS',
|
|
129
|
+
hightechExports: 'TX.VAL.TECH.MF.ZS',
|
|
53
130
|
};
|
|
54
131
|
// ─── CSV Parsing ─────────────────────────────────────────────────────────────
|
|
55
132
|
/** Known CSV header aliases for each World Bank field */
|
|
@@ -194,7 +271,16 @@ export function formatIndicatorValue(value, indicatorId) {
|
|
|
194
271
|
indicatorId === POLICY_INDICATORS.inflation ||
|
|
195
272
|
indicatorId === POLICY_INDICATORS.unemployment ||
|
|
196
273
|
indicatorId === POLICY_INDICATORS.trade ||
|
|
197
|
-
indicatorId === POLICY_INDICATORS.
|
|
274
|
+
indicatorId === POLICY_INDICATORS.taxRevenue ||
|
|
275
|
+
indicatorId === POLICY_INDICATORS.govExpenditure ||
|
|
276
|
+
indicatorId === POLICY_INDICATORS.militaryExpenditure ||
|
|
277
|
+
indicatorId === POLICY_INDICATORS.exportsGdp ||
|
|
278
|
+
indicatorId === POLICY_INDICATORS.healthExpenditure ||
|
|
279
|
+
indicatorId === POLICY_INDICATORS.educationExpenditure ||
|
|
280
|
+
indicatorId === POLICY_INDICATORS.internetUsers ||
|
|
281
|
+
indicatorId === POLICY_INDICATORS.renewableEnergy ||
|
|
282
|
+
indicatorId === POLICY_INDICATORS.rdExpenditure ||
|
|
283
|
+
indicatorId === POLICY_INDICATORS.hightechExports) {
|
|
198
284
|
return `${value.toFixed(1)}%`;
|
|
199
285
|
}
|
|
200
286
|
// CO2 emissions - metric tons per capita
|
|
@@ -232,12 +318,29 @@ export function buildEconomicContext(countryCode, countryName, indicatorData) {
|
|
|
232
318
|
const indicatorNames = {
|
|
233
319
|
[POLICY_INDICATORS.gdp]: 'GDP',
|
|
234
320
|
[POLICY_INDICATORS.gdpGrowth]: 'GDP Growth',
|
|
321
|
+
[POLICY_INDICATORS.gdpPerCapita]: 'GDP per Capita',
|
|
322
|
+
[POLICY_INDICATORS.gniPerCapita]: 'GNI per Capita',
|
|
235
323
|
[POLICY_INDICATORS.inflation]: 'Inflation',
|
|
236
324
|
[POLICY_INDICATORS.unemployment]: 'Unemployment',
|
|
325
|
+
[POLICY_INDICATORS.exportsGdp]: 'Exports (% of GDP)',
|
|
326
|
+
[POLICY_INDICATORS.fdiNet]: 'FDI Net Inflows',
|
|
237
327
|
[POLICY_INDICATORS.trade]: 'Trade (% of GDP)',
|
|
238
|
-
[POLICY_INDICATORS.
|
|
328
|
+
[POLICY_INDICATORS.taxRevenue]: 'Tax Revenue (% of GDP)',
|
|
329
|
+
[POLICY_INDICATORS.govExpenditure]: 'Gov. Expenditure (% of GDP)',
|
|
330
|
+
[POLICY_INDICATORS.militaryExpenditure]: 'Military Expenditure (% of GDP)',
|
|
239
331
|
[POLICY_INDICATORS.population]: 'Population',
|
|
240
|
-
[POLICY_INDICATORS.
|
|
332
|
+
[POLICY_INDICATORS.lifeExpectancy]: 'Life Expectancy',
|
|
333
|
+
[POLICY_INDICATORS.birthRate]: 'Birth Rate',
|
|
334
|
+
[POLICY_INDICATORS.deathRate]: 'Death Rate',
|
|
335
|
+
[POLICY_INDICATORS.internetUsers]: 'Internet Users (%)',
|
|
336
|
+
[POLICY_INDICATORS.healthExpenditure]: 'Health Expenditure (% of GDP)',
|
|
337
|
+
[POLICY_INDICATORS.physicians]: 'Physicians (per 1,000)',
|
|
338
|
+
[POLICY_INDICATORS.hospitalBeds]: 'Hospital Beds (per 1,000)',
|
|
339
|
+
[POLICY_INDICATORS.educationExpenditure]: 'Education Expenditure (% of GDP)',
|
|
340
|
+
[POLICY_INDICATORS.co2Emissions]: 'CO₂ Emissions',
|
|
341
|
+
[POLICY_INDICATORS.renewableEnergy]: 'Renewable Energy (%)',
|
|
342
|
+
[POLICY_INDICATORS.rdExpenditure]: 'R&D Expenditure (% of GDP)',
|
|
343
|
+
[POLICY_INDICATORS.hightechExports]: 'High-Tech Exports (%)',
|
|
241
344
|
};
|
|
242
345
|
for (const [indicatorId, dataPoints] of indicatorData) {
|
|
243
346
|
const recent = getMostRecentValue(dataPoints);
|