Skip to main content
Glama
nexusforge-tools

NexusForge EU Finance

Official

get_eu_unemployment

Read-onlyIdempotent

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

TableJSON Schema
NameRequiredDescriptionDefault
countriesNoList of EU country codes (e.g. ["DE", "FR", "ES"]). Use "EA20" for Eurozone. Omit for main EU countries.
monthsNoNumber of recent months to return (1-24). Default: 3.
ageNoAge group: TOTAL (all ages), Y15-24 (youth), Y25-74 (adults). Default: TOTAL.TOTAL

Implementation Reference

  • 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) }] };
          });
        },
      );
    }
  • 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) }] };
          });
        },
      );
    }
  • 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',
  • 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;
    }
  • 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'
    ]
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate readOnlyHint, destructiveHint, idempotentHint, openWorldHint. The description adds valuable behavioral context: data cached 24 hours, typical lag 30-60 days, seasonally adjusted, and default parameters. No contradiction with annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Approximately 10 sentences, well-structured: begins with core purpose, then output format, defaults, caching, and usage advice. Every sentence adds meaningful information without repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has three parameters and no output schema, the description fully covers output format, source, caching, lag, and usage scenarios like youth unemployment and trend analysis. It leaves no critical gaps for an agent to understand proper invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% with descriptions for all three parameters. The description enriches semantics by explaining default countries, providing usage tips for each parameter (e.g., using age for youth) and clarifying that countries list can include aggregates like EA20. It adds value beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool fetches monthly unemployment rates for EU countries from Eurostat (dataset: une_rt_m), seasonally adjusted, and specifies the output structure. It distinguishes from siblings by noting it is only for EU member states and EA20/EU27_2020 aggregates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides explicit guidance: when to use age=Y15-24 for youth unemployment, setting months=12+ for trend analysis, and warns that non-EU countries are not available. It also notes the data is seasonally adjusted so no additional correction is needed, and mentions typical Eurostat lag.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/nexusforge-tools/mcp-eu-finance'

If you have feedback or need assistance with the MCP directory API, please join our Discord server