get_kpi_data
Retrieve actual KPI data values for Swedish municipalities or organizational units. Filter by year and gender to analyze public sector performance metrics.
Instructions
Hämta faktiska KPI-datavärden för specifika kommuner eller organisationsenheter. Kan filtrera efter år och kön (T=Totalt, M=Män, K=Kvinnor).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| kpi_id | Yes | KPI-ID för att hämta data | |
| municipality_id | No | Kommun-ID (använd detta ELLER ou_id, inte båda) | |
| ou_id | No | Organisationsenhet-ID (använd detta ELLER municipality_id, inte båda) | |
| years | No | Filtrera efter specifika år (t.ex. [2020, 2021, 2022]) | |
| gender | No | Könsfilter: T=Totalt, M=Män, K=Kvinnor, all=visa alla | all |
Implementation Reference
- src/tools/data-tools.ts:75-146 (handler)The async handler function that executes the tool logic: validates input, constructs Kolada API endpoint based on municipality_id or ou_id, fetches KPI data, applies year and gender filters, logs execution, and returns formatted JSON result or error.handler: async (args: z.infer<typeof getKpiDataSchema>): Promise<ToolResult> => { const startTime = Date.now(); const { kpi_id, municipality_id, ou_id, years, gender } = args; logger.toolCall('get_kpi_data', { kpi_id, municipality_id, ou_id, years, gender }); if (!municipality_id && !ou_id) { return { content: [ { type: 'text', text: JSON.stringify({ error: 'INVALID_INPUT', message: 'Antingen municipality_id eller ou_id måste anges', suggestion: 'Ange municipality_id för kommundata eller ou_id för organisationsenhetsdata', }), }, ], isError: true, }; } try { // Kolada API v3 uses path-based URLs for data let endpoint: string; if (ou_id) { endpoint = `/oudata/kpi/${kpi_id}/ou/${ou_id}`; if (years && years.length > 0) { endpoint += `/year/${years.join(',')}`; } } else if (municipality_id) { endpoint = `/data/kpi/${kpi_id}/municipality/${municipality_id}`; if (years && years.length > 0) { endpoint += `/year/${years.join(',')}`; } } else { endpoint = `/data/kpi/${kpi_id}`; if (years && years.length > 0) { endpoint += `/year/${years.join(',')}`; } } let data = await koladaClient.fetchAllData<KPIData>(endpoint); // Apply gender filter data = filterByGender(data, gender); logger.toolResult('get_kpi_data', true, Date.now() - startTime); return { content: [ { type: 'text', text: JSON.stringify( { kpi_id, entity_id: municipality_id || ou_id, entity_type: municipality_id ? 'kommun' : 'organisationsenhet', gender_filter: gender, data_points: data, source: 'Kolada - Källa: Kolada', }, null, 2 ), }, ], }; } catch (error) { logger.toolResult('get_kpi_data', false, Date.now() - startTime); throw error; } },
- src/tools/data-tools.ts:22-28 (schema)Zod input schema defining parameters: kpi_id (required), municipality_id or ou_id (one required), optional years array, and gender filter.const getKpiDataSchema = z.object({ kpi_id: z.string().describe('KPI-ID för att hämta data'), municipality_id: z.string().optional().describe('Kommun-ID (använd detta ELLER ou_id, inte båda)'), ou_id: z.string().optional().describe('Organisationsenhet-ID (använd detta ELLER municipality_id, inte båda)'), years: z.array(z.number()).optional().describe('Filtrera efter specifika år (t.ex. [2020, 2021, 2022])'), gender: z.enum(['T', 'M', 'K', 'all']).default('all').describe('Könsfilter: T=Totalt, M=Män, K=Kvinnor, all=visa alla'), });
- src/tools/data-tools.ts:71-147 (registration)Registration of the get_kpi_data tool within the dataTools export object, including description, schema reference, annotations, and inline handler.get_kpi_data: { description: 'Hämta faktiska KPI-datavärden för specifika kommuner eller organisationsenheter. Kan filtrera efter år och kön (T=Totalt, M=Män, K=Kvinnor).', inputSchema: getKpiDataSchema, annotations: READ_ONLY_ANNOTATIONS, handler: async (args: z.infer<typeof getKpiDataSchema>): Promise<ToolResult> => { const startTime = Date.now(); const { kpi_id, municipality_id, ou_id, years, gender } = args; logger.toolCall('get_kpi_data', { kpi_id, municipality_id, ou_id, years, gender }); if (!municipality_id && !ou_id) { return { content: [ { type: 'text', text: JSON.stringify({ error: 'INVALID_INPUT', message: 'Antingen municipality_id eller ou_id måste anges', suggestion: 'Ange municipality_id för kommundata eller ou_id för organisationsenhetsdata', }), }, ], isError: true, }; } try { // Kolada API v3 uses path-based URLs for data let endpoint: string; if (ou_id) { endpoint = `/oudata/kpi/${kpi_id}/ou/${ou_id}`; if (years && years.length > 0) { endpoint += `/year/${years.join(',')}`; } } else if (municipality_id) { endpoint = `/data/kpi/${kpi_id}/municipality/${municipality_id}`; if (years && years.length > 0) { endpoint += `/year/${years.join(',')}`; } } else { endpoint = `/data/kpi/${kpi_id}`; if (years && years.length > 0) { endpoint += `/year/${years.join(',')}`; } } let data = await koladaClient.fetchAllData<KPIData>(endpoint); // Apply gender filter data = filterByGender(data, gender); logger.toolResult('get_kpi_data', true, Date.now() - startTime); return { content: [ { type: 'text', text: JSON.stringify( { kpi_id, entity_id: municipality_id || ou_id, entity_type: municipality_id ? 'kommun' : 'organisationsenhet', gender_filter: gender, data_points: data, source: 'Kolada - Källa: Kolada', }, null, 2 ), }, ], }; } catch (error) { logger.toolResult('get_kpi_data', false, Date.now() - startTime); throw error; } }, },
- src/server/handlers.ts:32-38 (registration)MCP server tool registry where dataTools (including get_kpi_data) is spread into allTools, making it available for list tools and call tool handlers.export const allTools = { ...kpiTools, ...municipalityTools, ...ouTools, ...dataTools, ...analysisTools, };
- src/tools/data-tools.ts:58-65 (helper)Helper function to filter KPI data by gender (T=Total, M=Men, K=Women, all), used in the get_kpi_data handler and other data tools.function filterByGender(data: KPIData[], gender: 'T' | 'M' | 'K' | 'all'): KPIData[] { if (gender === 'all') return data; return data.map(d => ({ ...d, values: d.values.filter(v => v.gender === gender || (!v.gender && gender === 'T')) })).filter(d => d.values.length > 0); }