All files / mcp wb-mcp-client.ts

57.69% Statements 15/26
65.51% Branches 19/29
75% Functions 3/4
57.69% Lines 15/26

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125                                                1x     1x     1x           1x                     8x                                     5x 2x 2x   3x 3x         2x 2x 2x           1x                                                                     2x          
// SPDX-FileCopyrightText: 2024-2026 Hack23 AB
// SPDX-License-Identifier: Apache-2.0
 
/**
 * @module MCP/WBMCPClient
 * @description World Bank MCP client — domain-specific tool wrappers for
 * the World Bank MCP server ({@link https://github.com/anshumax/world_bank_mcp_server}).
 *
 * Extends {@link MCPConnection} with World Bank-specific tool methods.
 * Provides economic indicator data for EU member states to enrich
 * European Parliament news articles with macroeconomic context.
 *
 * Environment variables:
 * - `WB_MCP_SERVER_PATH` — Override default server binary path
 * - `WB_MCP_GATEWAY_URL` — Use HTTP gateway transport instead of stdio
 * - `WB_MCP_GATEWAY_API_KEY` — API key for gateway authentication
 */
 
import { resolve, dirname } from 'path';
import { fileURLToPath } from 'url';
import { MCPConnection } from './mcp-connection.js';
import type { MCPToolResult, MCPClientOptions } from '../types/index.js';
 
/** npm binary name for the World Bank MCP server */
const WB_BINARY_NAME = 'worldbank-mcp';
 
/** Platform-specific binary filename (Windows uses .cmd shim) */
const WB_BINARY_FILE = process.platform === 'win32' ? `${WB_BINARY_NAME}.cmd` : WB_BINARY_NAME;
 
/** Default binary resolved from node_modules/.bin relative to this file's compiled location */
const WB_DEFAULT_SERVER = resolve(
  dirname(fileURLToPath(import.meta.url)),
  `../../node_modules/.bin/${WB_BINARY_FILE}`
);
 
/** Fallback payload when indicator data is unavailable (empty CSV) */
const INDICATOR_FALLBACK = '';
 
/**
 * MCP Client for World Bank economic data access.
 * Extends {@link MCPConnection} with World Bank-specific tool wrapper methods.
 *
 * Always supplies an explicit World Bank server path so the base class never
 * falls back to the European Parliament MCP server defaults.
 */
export class WorldBankMCPClient extends MCPConnection {
  constructor(options: MCPClientOptions = {}) {
    super({
      ...options,
      serverPath: options.serverPath ?? process.env['WB_MCP_SERVER_PATH'] ?? WB_DEFAULT_SERVER,
      gatewayUrl: options.gatewayUrl ?? process.env['WB_MCP_GATEWAY_URL'] ?? '',
      gatewayApiKey: options.gatewayApiKey ?? process.env['WB_MCP_GATEWAY_API_KEY'] ?? '',
      serverLabel: options.serverLabel ?? 'World Bank MCP Server',
    });
  }
 
  /**
   * Get economic indicator data for a specific country.
   *
   * Calls the `get_indicator_for_country` tool on the World Bank MCP server.
   *
   * @param countryId - World Bank country code (e.g., 'DEU' for Germany, 'FRA' for France)
   * @param indicatorId - World Bank indicator ID (e.g., 'NY.GDP.MKTP.CD' for GDP)
   * @returns MCP tool result with CSV-formatted indicator data, or empty text on error
   */
  async getIndicatorForCountry(countryId: string, indicatorId: string): Promise<MCPToolResult> {
    if (!countryId || !indicatorId) {
      console.warn('get_indicator_for_country called without required countryId or indicatorId');
      return { content: [{ type: 'text', text: INDICATOR_FALLBACK }] };
    }
    try {
      return await this.callTool('get_indicator_for_country', {
        country_id: countryId,
        indicator_id: indicatorId,
      });
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      console.warn('get_indicator_for_country not available:', message);
      return { content: [{ type: 'text', text: INDICATOR_FALLBACK }] };
    }
  }
}
 
/** Singleton World Bank MCP client instance */
let wbClientInstance: WorldBankMCPClient | null = null;
 
/**
 * Get or create singleton World Bank MCP client instance.
 *
 * Uses `WB_MCP_SERVER_PATH`, `WB_MCP_GATEWAY_URL`, and `WB_MCP_GATEWAY_API_KEY`
 * environment variables for configuration. Falls back to stdio transport
 * with the `worldbank-mcp` npm binary resolved from `node_modules/.bin`.
 *
 * @param options - Client options (overrides env vars)
 * @returns Connected World Bank MCP client
 */
export async function getWBMCPClient(options: MCPClientOptions = {}): Promise<WorldBankMCPClient> {
  if (!wbClientInstance) {
    const mergedOptions: MCPClientOptions = {
      ...options,
      maxConnectionAttempts: options.maxConnectionAttempts ?? 2,
      connectionRetryDelay: options.connectionRetryDelay ?? 1000,
    };
    const client = new WorldBankMCPClient(mergedOptions);
    try {
      await client.connect();
      wbClientInstance = client;
    } catch (error) {
      wbClientInstance = null;
      throw error;
    }
  }
  return wbClientInstance;
}
 
/**
 * Close and cleanup singleton World Bank MCP client
 */
export async function closeWBMCPClient(): Promise<void> {
  Iif (wbClientInstance) {
    wbClientInstance.disconnect();
    wbClientInstance = null;
  }
}