Skip to main content
Glama
Hug0x0

mcp-reunion

reunion_search_real_estate_transactions

Search the DVF database for real estate transactions in La Réunion by year, commune, property type, and value range. Get mutation details for price analysis and market trends.

Instructions

Search the DVF (Demande de Valeurs Foncières) database — France's open record of real-estate transactions registered with notaires — restricted to La Réunion. Each row is one mutation (sale, exchange, etc.) with date, value, property characteristics. Returns mutation ID, date, year, nature of mutation, VEFA flag (sale of future state of completion), sale value (EUR), INSEE codes, land area, built area, counts of houses/apartments/commercial premises, type code and label, department. Sorted by date descending. Use for price analysis, market trends, comparable sales.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
yearNoYear of mutation (4 digits, e.g. 2023)
inseeNoINSEE commune code (5 digits as string, e.g. "97411" for Saint-Denis). Substring match supported
typeNoProperty type label prefix match (libtypbien). Examples: "MAISON", "APPARTEMENT", "DEPENDANCE", "TERRAIN"
min_valueNoMinimum sale value in EUR (inclusive)
max_valueNoMaximum sale value in EUR (inclusive)
limitNoMax transactions to return (1-200, default 50)

Implementation Reference

  • The tool 'reunion_search_real_estate_transactions' is registered via server.tool() on line 16 within registerTerritoryTools(). The Zod schema for inputs (year, insee, type, min_value, max_value, limit) is defined on lines 19-26. The handler function is the async callback on lines 27-63 which queries the DVF dataset and returns structured transaction data.
    export function registerTerritoryTools(server: McpServer): void {
      server.tool(
        'reunion_search_real_estate_transactions',
        'Search the DVF (Demande de Valeurs Foncières) database — France\'s open record of real-estate transactions registered with notaires — restricted to La Réunion. Each row is one mutation (sale, exchange, etc.) with date, value, property characteristics. Returns mutation ID, date, year, nature of mutation, VEFA flag (sale of future state of completion), sale value (EUR), INSEE codes, land area, built area, counts of houses/apartments/commercial premises, type code and label, department. Sorted by date descending. Use for price analysis, market trends, comparable sales.',
        {
          year: z.number().int().optional().describe('Year of mutation (4 digits, e.g. 2023)'),
          insee: z.string().optional().describe('INSEE commune code (5 digits as string, e.g. "97411" for Saint-Denis). Substring match supported'),
          type: z.string().optional().describe('Property type label prefix match (libtypbien). Examples: "MAISON", "APPARTEMENT", "DEPENDANCE", "TERRAIN"'),
          min_value: z.number().optional().describe('Minimum sale value in EUR (inclusive)'),
          max_value: z.number().optional().describe('Maximum sale value in EUR (inclusive)'),
          limit: z.number().int().min(1).max(200).default(50).describe('Max transactions to return (1-200, default 50)'),
        },
        async ({ year, insee, type, min_value, max_value, limit }) => {
          try {
            const data = await client.getRecords<RecordObject>(DATASET_DVF, {
              where: buildWhere([
                year !== undefined ? `datemut >= date'${year}-01-01' AND datemut < date'${year + 1}-01-01'` : undefined,
                insee ? `l_codinsee LIKE ${quote(`%${insee}%`)}` : undefined,
                type ? `libtypbien LIKE ${quote(`${type}%`)}` : undefined,
                min_value !== undefined ? `valeurfonc >= ${min_value}` : undefined,
                max_value !== undefined ? `valeurfonc <= ${max_value}` : undefined,
              ]),
              order_by: 'datemut DESC',
              limit,
            });
            return jsonResult({
              total_transactions: data.total_count,
              transactions: data.results.map((row) => ({
                mutation_id: pickString(row, ['idmutation']),
                date: pickString(row, ['datemut']),
                year: pickNumber(row, ['anneemut']),
                nature: pickString(row, ['libnatmut']),
                vefa: pickString(row, ['vefa']),
                value_eur: pickNumber(row, ['valeurfonc']),
                insee_codes: pickString(row, ['l_codinsee']),
                land_area_m2: pickNumber(row, ['sterr']),
                built_area_m2: pickNumber(row, ['sbati']),
                nb_houses: pickNumber(row, ['nblocmai']),
                nb_apartments: pickNumber(row, ['nblocapt']),
                nb_commercial: pickNumber(row, ['nblocact']),
                type_code: pickString(row, ['codtypbien']),
                type_label: pickString(row, ['libtypbien']),
                department: pickString(row, ['dep_name']),
              })),
            });
          } catch (error) {
            return errorResult(error instanceof Error ? error.message : 'Failed to search real-estate transactions');
          }
        }
      );
  • Handler function for reunion_search_real_estate_transactions: builds ODSQL WHERE clause from filters, queries the 'demande-de-valeurs-foncierespublic' dataset via client.getRecords(), maps results to a structured response with mutation_id, date, year, nature, vefa, value_eur, insee_codes, land_area_m2, built_area_m2, nb_houses, nb_apartments, nb_commercial, type_code, type_label, department. Sorted by date descending. Returns total_transactions count.
    async ({ year, insee, type, min_value, max_value, limit }) => {
      try {
        const data = await client.getRecords<RecordObject>(DATASET_DVF, {
          where: buildWhere([
            year !== undefined ? `datemut >= date'${year}-01-01' AND datemut < date'${year + 1}-01-01'` : undefined,
            insee ? `l_codinsee LIKE ${quote(`%${insee}%`)}` : undefined,
            type ? `libtypbien LIKE ${quote(`${type}%`)}` : undefined,
            min_value !== undefined ? `valeurfonc >= ${min_value}` : undefined,
            max_value !== undefined ? `valeurfonc <= ${max_value}` : undefined,
          ]),
          order_by: 'datemut DESC',
          limit,
        });
        return jsonResult({
          total_transactions: data.total_count,
          transactions: data.results.map((row) => ({
            mutation_id: pickString(row, ['idmutation']),
            date: pickString(row, ['datemut']),
            year: pickNumber(row, ['anneemut']),
            nature: pickString(row, ['libnatmut']),
            vefa: pickString(row, ['vefa']),
            value_eur: pickNumber(row, ['valeurfonc']),
            insee_codes: pickString(row, ['l_codinsee']),
            land_area_m2: pickNumber(row, ['sterr']),
            built_area_m2: pickNumber(row, ['sbati']),
            nb_houses: pickNumber(row, ['nblocmai']),
            nb_apartments: pickNumber(row, ['nblocapt']),
            nb_commercial: pickNumber(row, ['nblocact']),
            type_code: pickString(row, ['codtypbien']),
            type_label: pickString(row, ['libtypbien']),
            department: pickString(row, ['dep_name']),
          })),
        });
      } catch (error) {
        return errorResult(error instanceof Error ? error.message : 'Failed to search real-estate transactions');
      }
    }
  • Zod input schema for the tool: year (int, optional), insee (string, optional, substring match on INSEE code), type (string, optional, prefix match on property type label), min_value (number, optional), max_value (number, optional), limit (int, 1-200, default 50).
    {
      year: z.number().int().optional().describe('Year of mutation (4 digits, e.g. 2023)'),
      insee: z.string().optional().describe('INSEE commune code (5 digits as string, e.g. "97411" for Saint-Denis). Substring match supported'),
      type: z.string().optional().describe('Property type label prefix match (libtypbien). Examples: "MAISON", "APPARTEMENT", "DEPENDANCE", "TERRAIN"'),
      min_value: z.number().optional().describe('Minimum sale value in EUR (inclusive)'),
      max_value: z.number().optional().describe('Maximum sale value in EUR (inclusive)'),
      limit: z.number().int().min(1).max(200).default(50).describe('Max transactions to return (1-200, default 50)'),
    },
  • Import of registerTerritoryTools from './territory.js', which contains the registration of reunion_search_real_estate_transactions.
    import { registerTerritoryTools } from './territory.js';
  • Call to registerTerritoryTools(server) inside registerAllTools(), which triggers the registration of all territory tools including reunion_search_real_estate_transactions.
    registerTerritoryTools(server);
Behavior3/5

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

Describes data returned and sorting (date descending). No annotations, but the description implies read-only search. Does not mention rate limits or auth, though for a search tool that is acceptable. No contradiction with annotations (none).

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

Conciseness3/5

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

Single paragraph is reasonably dense but could be more concise. Front-loads purpose but includes some redundant phrasing. Not overly long.

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

Completeness4/5

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

Covers return fields, sorting, and typical use cases. No output schema, but description compensates by listing fields. 0 required params, all optional. Missing pagination details beyond limit parameter, but that's covered in schema.

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

Parameters3/5

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

All 6 parameters have schema descriptions (100% coverage). The tool description does not add significant meaning beyond the schema; it lists return fields but not parameter usage tips. Baseline 3 is appropriate.

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?

Clearly states it searches DVF database for real-estate transactions in La Réunion. Lists each returned field and use cases (price analysis, market trends). Distinct from siblings like reunion_search_building_permits.

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

Usage Guidelines2/5

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

No explicit guidance on when to use this tool vs alternatives. Does not mention when not to use or provide alternative tool names. The list of sibling tools exists but no comparative advice.

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/Hug0x0/mcp-reunion'

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