m2local

A property search assistant for Argentina, built around a shared listing catalog that people could search through chat and agents could query through MCP.

Period
October 2025 – January 2026
Role
Engineer
Team
Taecontrol
Stack
Laravel 12, React 19, Inertia 2, Filament 4, Meilisearch, LarAgent 0.8, OpenRouter, Horizon
Status
Closed

With m2local, I wanted someone searching for a home in Argentina to describe what they needed in a sentence. They could ask for a small apartment near a neighborhood within a budget, then refine the search in conversation. The application would translate that request into filters over listings collected from property portals.

That meant building the catalog before the conversation could be useful. Different sites described properties differently. We used one Property model for search and kept the scraped pages and extraction records separately. If an extraction needed to change, we could go back to its source instead of treating the processed listing as the only record.

Firecrawl collected pages. LocationIQ provided geocoding. Separate agents extracted property details and analyzed images. Filament gave us an admin panel to inspect the sources and scrape runs, including work that had failed. Those inspection tools were necessary because an agent's answer depended on data produced by several earlier jobs.

The chat ran asynchronously. Laravel saved the user's message as pending and sent a job to the queue. The browser could show that the message had arrived while the model worked on a response. Horizon handled the jobs.

I kept the search agent's access narrow. It called a structured search_properties tool, with a limit of five searches per turn. The response format separated results from a clarification question or an ordinary reply. The application could then render property records itself, instead of asking the model to build the whole result page as text.

An authenticated MCP server exposed the same search action to external agents. It used the catalog and search rules already built for the chat. We also built a waitlist and invitation flow for controlling access.

We stopped before a public launch. The repository remains public, but there is no public product to use. I would not treat a completed ingestion pipeline and a working chat as evidence that we had found an audience.

The useful lesson was how much the search depended on the records underneath it. Keeping the raw extractions helped us investigate bad answers. Giving the model a specific search tool made its choices easier to inspect. I would make those decisions again, and spend time with people looking for a home earlier in the project.