get_eu_unemployment
Retrieve monthly seasonally adjusted unemployment rates for EU countries and aggregates from Eurostat, as a percentage of the active population. Specify country codes, time span, and age group (e.g., youth or total).
Instructions
Fetches monthly unemployment rates for EU countries from Eurostat (dataset: une_rt_m), seasonally adjusted, as a percentage of the active population. Returns a JSON object with: data (array of objects containing country as full name, period in YYYY-MM format, rate as a numeric percentage, age_group, and sex), unit ("Percentage of active population (%)"), source, and retrieved_at as ISO 8601. Defaults to TOTAL age group for EA20, EU27_2020, DE, FR, IT, ES, PL, NL over the last 3 months. Data is cached 24 hours. USAGE: Use age=Y15-24 for youth unemployment, which is typically 2-3x the overall rate. Data is seasonally adjusted (SA) — do not apply additional seasonal correction. Typical Eurostat lag is 30-60 days after the reference month. Set months=12 or more for trend and cyclical analysis. Non-EU countries (e.g. US, UK) are not available — use this tool only for EU member states and EA20/EU27_2020 aggregates.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| countries | No | List of EU country codes (e.g. ["DE", "FR", "ES"]). Use "EA20" for Eurozone. Omit for main EU countries. | |
| months | No | Number of recent months to return (1-24). Default: 3. | |
| age | No | Age group: TOTAL (all ages), Y15-24 (youth), Y25-74 (adults). Default: TOTAL. | TOTAL |
Implementation Reference
- src/tools/eu-unemployment.ts:36-116 (handler)The main handler for the get_eu_unemployment tool. Registers the tool with MCP server, fetches unemployment data from Eurostat (dataset: une_rt_m), parses the JSON response, caches results for 24 hours, and returns formatted JSON with country, period, rate, age_group, and sex fields.
export function registerEuUnemploymentTool(server: McpServer): void { server.tool( 'get_eu_unemployment', 'Fetches monthly unemployment rates for EU countries from Eurostat (dataset: une_rt_m), seasonally adjusted, as a percentage of the active population. Returns a JSON object with: `data` (array of objects containing `country` as full name, `period` in YYYY-MM format, `rate` as a numeric percentage, `age_group`, and `sex`), `unit` ("Percentage of active population (%)"), `source`, and `retrieved_at` as ISO 8601. Defaults to TOTAL age group for EA20, EU27_2020, DE, FR, IT, ES, PL, NL over the last 3 months. Data is cached 24 hours. USAGE: Use age=Y15-24 for youth unemployment, which is typically 2-3x the overall rate. Data is seasonally adjusted (SA) — do not apply additional seasonal correction. Typical Eurostat lag is 30-60 days after the reference month. Set months=12 or more for trend and cyclical analysis. Non-EU countries (e.g. US, UK) are not available — use this tool only for EU member states and EA20/EU27_2020 aggregates.', { countries: z .array(z.string().min(2).max(12).toUpperCase()) .optional() .describe('List of EU country codes (e.g. ["DE", "FR", "ES"]). Use "EA20" for Eurozone. Omit for main EU countries.'), months: z .number() .int() .min(1) .max(24) .optional() .default(3) .describe('Number of recent months to return (1-24). Default: 3.'), age: z .enum(['TOTAL', 'Y15-74', 'Y15-24', 'Y25-74']) .optional() .default('TOTAL') .describe('Age group: TOTAL (all ages), Y15-24 (youth), Y25-74 (adults). Default: TOTAL.'), }, READ_ONLY_PUBLIC_API, async ({ countries, months, age }) => { return withMcpMiddleware({ serverName: SERVER_NAME, toolName: 'get_eu_unemployment' }, async () => { const targetCountries = countries?.length ? countries : ['EA20', 'EU27_2020', 'DE', 'FR', 'IT', 'ES', 'PL', 'NL']; const params = { countries: targetCountries, months, age }; const cacheKey = `get_eu_unemployment:${hashParams(params as Record<string, unknown>)}`; const cached = await cacheGet<EuUnemploymentResult>(cacheKey); if (cached) { return { content: [{ type: 'text' as const, text: JSON.stringify(cached, null, 2) }] }; } const searchParams = new URLSearchParams({ sex: 'T', // Total (both sexes) age: age ?? 'TOTAL', unit: 'PC_ACT', // Percentage of active population s_adj: 'SA', // Seasonally adjusted lastTimePeriod: String(months ?? 3), format: 'JSON', lang: 'EN', }); for (const country of targetCountries) { searchParams.append('geo', country); } const url = `${EUROSTAT_BASE}/une_rt_m?${searchParams}`; const res = await fetch(url, { signal: AbortSignal.timeout(15_000) }); if (!res.ok) { return makeMcpError( `Eurostat API returned ${res.status} for unemployment data`, 'SOURCE_UNAVAILABLE', ); } const json = (await res.json()) as EurostatJsonData; const data = parseUnemploymentResponse(json, targetCountries, age ?? 'TOTAL'); if (!data.length) { return makeMcpError('No unemployment data found for the requested countries', 'SOURCE_UNAVAILABLE'); } const result: EuUnemploymentResult = { data, unit: 'Percentage of active population (%)', source: 'Eurostat — Unemployment by sex and age — monthly data (une_rt_m)', retrieved_at: new Date().toISOString(), }; await cacheSet(cacheKey, result, CACHE_TTL); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }; }); }, ); } - src/tools/eu-unemployment.ts:36-116 (schema)Input schema defined via Zod: countries (optional array of uppercase 2-12 char codes), months (optional 1-24, default 3), age (enum TOTAL/Y15-74/Y15-24/Y25-74, default TOTAL). Output type is EuUnemploymentResult with data array of UnemploymentDataPoint objects.
export function registerEuUnemploymentTool(server: McpServer): void { server.tool( 'get_eu_unemployment', 'Fetches monthly unemployment rates for EU countries from Eurostat (dataset: une_rt_m), seasonally adjusted, as a percentage of the active population. Returns a JSON object with: `data` (array of objects containing `country` as full name, `period` in YYYY-MM format, `rate` as a numeric percentage, `age_group`, and `sex`), `unit` ("Percentage of active population (%)"), `source`, and `retrieved_at` as ISO 8601. Defaults to TOTAL age group for EA20, EU27_2020, DE, FR, IT, ES, PL, NL over the last 3 months. Data is cached 24 hours. USAGE: Use age=Y15-24 for youth unemployment, which is typically 2-3x the overall rate. Data is seasonally adjusted (SA) — do not apply additional seasonal correction. Typical Eurostat lag is 30-60 days after the reference month. Set months=12 or more for trend and cyclical analysis. Non-EU countries (e.g. US, UK) are not available — use this tool only for EU member states and EA20/EU27_2020 aggregates.', { countries: z .array(z.string().min(2).max(12).toUpperCase()) .optional() .describe('List of EU country codes (e.g. ["DE", "FR", "ES"]). Use "EA20" for Eurozone. Omit for main EU countries.'), months: z .number() .int() .min(1) .max(24) .optional() .default(3) .describe('Number of recent months to return (1-24). Default: 3.'), age: z .enum(['TOTAL', 'Y15-74', 'Y15-24', 'Y25-74']) .optional() .default('TOTAL') .describe('Age group: TOTAL (all ages), Y15-24 (youth), Y25-74 (adults). Default: TOTAL.'), }, READ_ONLY_PUBLIC_API, async ({ countries, months, age }) => { return withMcpMiddleware({ serverName: SERVER_NAME, toolName: 'get_eu_unemployment' }, async () => { const targetCountries = countries?.length ? countries : ['EA20', 'EU27_2020', 'DE', 'FR', 'IT', 'ES', 'PL', 'NL']; const params = { countries: targetCountries, months, age }; const cacheKey = `get_eu_unemployment:${hashParams(params as Record<string, unknown>)}`; const cached = await cacheGet<EuUnemploymentResult>(cacheKey); if (cached) { return { content: [{ type: 'text' as const, text: JSON.stringify(cached, null, 2) }] }; } const searchParams = new URLSearchParams({ sex: 'T', // Total (both sexes) age: age ?? 'TOTAL', unit: 'PC_ACT', // Percentage of active population s_adj: 'SA', // Seasonally adjusted lastTimePeriod: String(months ?? 3), format: 'JSON', lang: 'EN', }); for (const country of targetCountries) { searchParams.append('geo', country); } const url = `${EUROSTAT_BASE}/une_rt_m?${searchParams}`; const res = await fetch(url, { signal: AbortSignal.timeout(15_000) }); if (!res.ok) { return makeMcpError( `Eurostat API returned ${res.status} for unemployment data`, 'SOURCE_UNAVAILABLE', ); } const json = (await res.json()) as EurostatJsonData; const data = parseUnemploymentResponse(json, targetCountries, age ?? 'TOTAL'); if (!data.length) { return makeMcpError('No unemployment data found for the requested countries', 'SOURCE_UNAVAILABLE'); } const result: EuUnemploymentResult = { data, unit: 'Percentage of active population (%)', source: 'Eurostat — Unemployment by sex and age — monthly data (une_rt_m)', retrieved_at: new Date().toISOString(), }; await cacheSet(cacheKey, result, CACHE_TTL); return { content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }] }; }); }, ); } - src/tools/eu-unemployment.ts:36-38 (registration)Registration of the tool via server.tool('get_eu_unemployment', ...) in the registerEuUnemploymentTool function, exported and called from http-entry.ts line 29.
export function registerEuUnemploymentTool(server: McpServer): void { server.tool( 'get_eu_unemployment', - src/tools/eu-unemployment.ts:118-156 (helper)Helper function parseUnemploymentResponse that takes the raw Eurostat JSON and extracts unemployment data points by iterating over geo and time dimensions.
function parseUnemploymentResponse( json: EurostatJsonData, countries: string[], ageGroup: string, ): UnemploymentDataPoint[] { const geoIndex = json.dimension.geo.category.index; const geoLabel = json.dimension.geo.category.label; const timeIndex = json.dimension.time.category.index; const timeByPos: Record<number, string> = {}; for (const [period, pos] of Object.entries(timeIndex)) { timeByPos[pos] = period; } const geoSize = json.size[json.size.length - 2]; const timeSize = json.size[json.size.length - 1]; const results: UnemploymentDataPoint[] = []; for (const country of countries) { const geoPos = geoIndex[country]; if (geoPos === undefined) continue; for (let t = timeSize - 1; t >= 0; t--) { const valueIndex = geoPos * timeSize + t; const value = json.value[String(valueIndex)]; if (value !== null && value !== undefined) { results.push({ country: geoLabel[country] ?? country, period: timeByPos[t] ?? 'unknown', rate: value, age_group: ageGroup, sex: 'Total', }); } } } return results; } - src/http-entry.ts:41-48 (registration)Lists get_eu_unemployment in the MCP_WELL_KNOWN tools array for .well-known/mcp.json discovery.
tools: [ 'get_ecb_rates', 'get_euro_exchange', 'get_eu_inflation', 'get_eu_gdp', 'get_eu_unemployment', 'compare_eu_economies' ]