reunion_commune_profile
Fetch a complete profile of a commune in La Réunion by merging data from 8 sources including population, schools, businesses, and accidents. Get a single structured snapshot with inline error reporting for missing data.
Instructions
Comprehensive cross-dataset snapshot of one La Réunion commune. Joins 8 sources in parallel (population, QPV count and list, IRIS count, school count, priority-education school count, active SIRENE establishments, 2019 road-accidents count, museums count and list) into a single structured response. Failures on individual dimensions are reported inline rather than failing the whole call. Use reunion_find_commune first if the commune name might be misspelled. For side-by-side multi-commune comparison use reunion_compare_communes.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| commune | Yes | Commune name, used as case-sensitive prefix match. Examples: "Saint-Denis", "Le Tampon", "Saint-Pierre", "L'Étang-Salé" |
Implementation Reference
- src/modules/commune.ts:32-177 (registration)Registration: registerCommuneTools registers 'reunion_commune_profile' on the MCP server via server.tool()
export function registerCommuneTools(server: McpServer): void { server.tool( 'reunion_commune_profile', 'Comprehensive cross-dataset snapshot of one La Réunion commune. Joins 8 sources in parallel (population, QPV count and list, IRIS count, school count, priority-education school count, active SIRENE establishments, 2019 road-accidents count, museums count and list) into a single structured response. Failures on individual dimensions are reported inline rather than failing the whole call. Use reunion_find_commune first if the commune name might be misspelled. For side-by-side multi-commune comparison use reunion_compare_communes.', { commune: z.string().describe('Commune name, used as case-sensitive prefix match. Examples: "Saint-Denis", "Le Tampon", "Saint-Pierre", "L\'Étang-Salé"'), }, async ({ commune }) => { const prefix = `${commune}%`; const [ population, qpv, iris, schools, priorityEd, sirene, accidents, museums, ] = await Promise.all([ settle( 'population', // Dataset is national — scope to département 974 to avoid matches // like "Villiers-Saint-Denis" (Aisne) when user types "Saint-Denis". client.getRecords<RecordObject>('population-francaise-communespublic', { where: `code_departement = ${quote('974')} AND nom_de_la_commune LIKE ${quote(prefix)}`, order_by: 'annee_recensement DESC', limit: 1, }) ), settle( 'qpv', client.getRecords<RecordObject>('quartiers-prioritaires-de-la-politique-de-la-ville-qpv', { where: `commune_qp LIKE ${quote(prefix)}`, limit: 50, }) ), settle( 'iris', client.getRecords<RecordObject>('iris-millesime-france', { where: `com_name LIKE ${quote(prefix)}`, limit: 100, }) ), settle( 'schools', client.getRecords<RecordObject>( 'adresse-et-geolocalisation-des-etablissements-d-enseignement-du-premier-et-secon', { where: `libelle_commune LIKE ${quote(prefix)}`, limit: 1, } ) ), settle( 'priority_education', client.getRecords<RecordObject>('etablissements-de-l-education-prioritaire-a-la-reunion', { where: `nom_commune LIKE ${quote(prefix)}`, limit: 1, }) ), settle( 'sirene', client.getRecords<RecordObject>('base-sirene-v3-lareunion', { where: `libellecommuneetablissement LIKE ${quote(prefix)} AND etatadministratifetablissement = ${quote('Actif')}`, limit: 1, }) ), settle( 'accidents_2019', client.getRecords<RecordObject>( 'bases-de-donnees-annuelles-des-accidents-corporels-de-la-circulation-routiere', { where: `com_name LIKE ${quote(prefix)} AND an = 2019`, limit: 1, } ) ), settle( 'museums', client.getRecords<RecordObject>('liste-des-musees-de-la-reunion', { where: `commune LIKE ${quote(prefix)}`, limit: 20, }) ), ]); const populationRow = population.value?.results[0]; const dimensions = { resolved: { query: commune, matched_commune: populationRow ? pickString(populationRow, ['nom_de_la_commune']) : null, insee_code: populationRow ? pickString(populationRow, ['code_insee']) : null, epci: populationRow ? pickString(populationRow, ['libepci']) : null, }, population: population.error ? { error: population.error } : populationRow ? { census_year: pickNumber(populationRow, ['annee_recensement']), total: pickNumber(populationRow, ['population_totale']), municipal: pickNumber(populationRow, ['population_municipale']), area_km2: pickNumber(populationRow, ['superficie']), } : null, territory: { iris_count: iris.error ? null : iris.value?.total_count ?? 0, qpv_count: qpv.error ? null : qpv.value?.total_count ?? 0, qpv_list: qpv.value?.results.map((row) => ({ code: pickString(row, ['code_qp']), name: pickString(row, ['nom_qp']), })) ?? [], }, education: { schools_count: schools.error ? null : schools.value?.total_count ?? 0, priority_education_schools: priorityEd.error ? null : priorityEd.value?.total_count ?? 0, }, economy: { active_sirene_establishments: sirene.error ? null : sirene.value?.total_count ?? 0, }, safety: { accidents_2019: accidents.error ? null : accidents.value?.total_count ?? 0, }, culture: { museums_count: museums.error ? null : museums.value?.total_count ?? 0, museums: museums.value?.results.map((row) => ({ name: pickString(row, ['nom_officiel_du_musee']), museofile_id: pickString(row, ['identifiant_museofile']), })) ?? [], }, errors: [population, qpv, iris, schools, priorityEd, sirene, accidents, museums] .filter((r) => r.error) .map((r) => ({ dimension: r.label, error: r.error })), }; if (!populationRow && population.error) { return errorResult( `Commune "${commune}" not found or population dataset unreachable: ${population.error}` ); } return jsonResult(dimensions); } ); - src/modules/commune.ts:39-177 (handler)Handler: The async callback receiving {commune}, querying 8 data sources in parallel via settle() and returning a structured JSON profile
async ({ commune }) => { const prefix = `${commune}%`; const [ population, qpv, iris, schools, priorityEd, sirene, accidents, museums, ] = await Promise.all([ settle( 'population', // Dataset is national — scope to département 974 to avoid matches // like "Villiers-Saint-Denis" (Aisne) when user types "Saint-Denis". client.getRecords<RecordObject>('population-francaise-communespublic', { where: `code_departement = ${quote('974')} AND nom_de_la_commune LIKE ${quote(prefix)}`, order_by: 'annee_recensement DESC', limit: 1, }) ), settle( 'qpv', client.getRecords<RecordObject>('quartiers-prioritaires-de-la-politique-de-la-ville-qpv', { where: `commune_qp LIKE ${quote(prefix)}`, limit: 50, }) ), settle( 'iris', client.getRecords<RecordObject>('iris-millesime-france', { where: `com_name LIKE ${quote(prefix)}`, limit: 100, }) ), settle( 'schools', client.getRecords<RecordObject>( 'adresse-et-geolocalisation-des-etablissements-d-enseignement-du-premier-et-secon', { where: `libelle_commune LIKE ${quote(prefix)}`, limit: 1, } ) ), settle( 'priority_education', client.getRecords<RecordObject>('etablissements-de-l-education-prioritaire-a-la-reunion', { where: `nom_commune LIKE ${quote(prefix)}`, limit: 1, }) ), settle( 'sirene', client.getRecords<RecordObject>('base-sirene-v3-lareunion', { where: `libellecommuneetablissement LIKE ${quote(prefix)} AND etatadministratifetablissement = ${quote('Actif')}`, limit: 1, }) ), settle( 'accidents_2019', client.getRecords<RecordObject>( 'bases-de-donnees-annuelles-des-accidents-corporels-de-la-circulation-routiere', { where: `com_name LIKE ${quote(prefix)} AND an = 2019`, limit: 1, } ) ), settle( 'museums', client.getRecords<RecordObject>('liste-des-musees-de-la-reunion', { where: `commune LIKE ${quote(prefix)}`, limit: 20, }) ), ]); const populationRow = population.value?.results[0]; const dimensions = { resolved: { query: commune, matched_commune: populationRow ? pickString(populationRow, ['nom_de_la_commune']) : null, insee_code: populationRow ? pickString(populationRow, ['code_insee']) : null, epci: populationRow ? pickString(populationRow, ['libepci']) : null, }, population: population.error ? { error: population.error } : populationRow ? { census_year: pickNumber(populationRow, ['annee_recensement']), total: pickNumber(populationRow, ['population_totale']), municipal: pickNumber(populationRow, ['population_municipale']), area_km2: pickNumber(populationRow, ['superficie']), } : null, territory: { iris_count: iris.error ? null : iris.value?.total_count ?? 0, qpv_count: qpv.error ? null : qpv.value?.total_count ?? 0, qpv_list: qpv.value?.results.map((row) => ({ code: pickString(row, ['code_qp']), name: pickString(row, ['nom_qp']), })) ?? [], }, education: { schools_count: schools.error ? null : schools.value?.total_count ?? 0, priority_education_schools: priorityEd.error ? null : priorityEd.value?.total_count ?? 0, }, economy: { active_sirene_establishments: sirene.error ? null : sirene.value?.total_count ?? 0, }, safety: { accidents_2019: accidents.error ? null : accidents.value?.total_count ?? 0, }, culture: { museums_count: museums.error ? null : museums.value?.total_count ?? 0, museums: museums.value?.results.map((row) => ({ name: pickString(row, ['nom_officiel_du_musee']), museofile_id: pickString(row, ['identifiant_museofile']), })) ?? [], }, errors: [population, qpv, iris, schools, priorityEd, sirene, accidents, museums] .filter((r) => r.error) .map((r) => ({ dimension: r.label, error: r.error })), }; if (!populationRow && population.error) { return errorResult( `Commune "${commune}" not found or population dataset unreachable: ${population.error}` ); } return jsonResult(dimensions); } ); - src/modules/commune.ts:36-38 (schema)Schema: Zod schema defining the 'commune' input parameter (string, described as case-sensitive prefix match)
{ commune: z.string().describe('Commune name, used as case-sensitive prefix match. Examples: "Saint-Denis", "Le Tampon", "Saint-Pierre", "L\'Étang-Salé"'), }, - src/modules/commune.ts:24-30 (helper)Helper: The settle() function that wraps promises to report individual dimension errors inline
async function settle<T>(label: string, p: Promise<T>): Promise<{ label: string; value?: T; error?: string }> { try { return { label, value: await p }; } catch (error) { return { label, error: error instanceof Error ? error.message : String(error) }; } } - src/modules/index.ts:33-56 (registration)Registration: registerAllTools in modules/index.ts calls registerCommuneTools(server) to activate the tool
export function registerAllTools(server: McpServer): void { registerAdministrationTools(server); registerCatalogTools(server); registerCommuneTools(server); registerCultureTools(server); registerEconomyTools(server); registerEducationTools(server); registerEmploymentTools(server); registerEnvironmentTools(server); registerFacilityTools(server); registerGeographyTools(server); registerHealthTools(server); registerHospitalityTools(server); registerHousingTools(server); registerNationalElectionsTools(server); registerPossessionTools(server); registerSocialTools(server); registerTelecomTools(server); registerTerritoryTools(server); registerTourismTools(server); registerTransportTools(server); registerUrbanismTools(server); registerWeatherTools(server); }