booli-mcp
This server provides read-only access to Swedish property data from Booli.se, routing requests through your browser to bypass bot protection. It supports the following tools:
booli_search_areas: Resolve a place name (e.g. "Nacka", "Södermalm") to Booli area IDs for use in other tools.booli_search_listings: Search active for-sale listings filtered by area, price (SEK), rooms, living area (m²), plot size, property type, construction year, and new construction status.booli_get_listing: Retrieve full details for a specific property (active or sold) using its Booli residence ID.booli_search_sold: Look up sold properties (slutpriser) with final achieved prices, over/under-asking percentages, and filters for sold date, price, size, and property type.booli_market_stats: Compute aggregate market statistics for an area, including median/average sold price, price per m², and average over/under-asking percentage.booli_healthcheck: Verify connectivity to Booli's data path (direct or via browser bridge) and measure response time.
All monetary values are in SEK and areas in m². Queries can be scoped by Booli area ID or free-text location.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@booli-mcpShow me sold prices in Göteborg"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
booli-mcp
An MCP server for Booli, the Swedish property portal — search active for-sale listings, sold prices (slutpriser), resolve areas, and compute market statistics, all from Claude.
Developed and maintained by AI (Claude Code). Use at your own discretion and within booli.se's terms of use.
How it works
Booli fronts www.booli.se — including its GraphQL API — with a Cloudflare bot wall that blocks server-side clients. booli-mcp therefore reads Booli's consumer GraphQL API by routing each query through your own signed-in www.booli.se browser tab via the fetchproxy bridge (the Transporter extension), reusing your Cloudflare-cleared session. No Booli login is required — just a normal page view. All tools are read-only.
BOOLI_TRANSPORT selects the path: auto (default — direct fetch first,
browser-bridge fallback when walled), fetchproxy (always the bridge), or
direct. The fetchproxy fleet shares WS port 37149 (BOOLI_WS_PORT).
Related MCP server: Idealista7 MCP Server
Setup
Install the Transporter (fetchproxy) browser extension and keep a www.booli.se tab open.
On the first request, approve the one-time pairing prompt in Transporter.
Run
booli_healthcheckto confirm the path is working. Itstransportfield says which leg served the probe (directorfetchproxy) and, once the bridge exists,bridge.session_statesays whether the Transporter extension islinked,pair_pending(approve the pair code it names), orextension_disconnected.
Install
// mcp config
{
"mcpServers": {
"booli": {
"command": "npx",
"args": ["-y", "@chrischall/booli-mcp"]
}
}
}Tools
Tool | What it does |
| Resolve a place name to Booli area ids |
| Search active for-sale listings by area + filters |
| Full detail for one property (active or sold) by residence id |
| Search sold listings (slutpriser) with final prices |
| Median/average sold-price statistics for an area |
| Probe the data path and report |
Searches scope by area_id (from booli_search_areas) or a free-text
location. Money is SEK, areas m². See
docs/BOOLI-API.md for the underlying GraphQL API.
Development
npm install
npm test # vitest, no network
npm run build # tsc + esbuild bundleLicense
MIT
Available Tools
6 toolsbooli_get_listingGet a Booli propertyARead-onlyIdempotent
Full detail for one property by its Booli residence id — the number in a booli.se/bostad/ URL, or the residence_id from a search result. Works for both active and sold properties. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| view | No | Response shape: "compact" (default) drops fields the response already carries elsewhere; "full" returns every field this server understands. compact returns the slim PropertySummary/detail projection; "full" returns Booli's whole GraphQL node. | |
| residence_id | Yes | The property's residence id (e.g. "4370936" from /bostad/4370936). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, so the safety profile is covered. The description reinforces 'Read-only' and adds the useful behavioral detail that both active and sold properties are supported, but it does not add substantial new behavioral context beyond that.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three short sentences with no filler. The core purpose is front-loaded, and every sentence earns its place by conveying scope, input origin, or safety.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple single-resource getter, this is complete: it names the required identifier, defines its provenance, notes optional response shape via the view parameter, and states applicability to active and sold properties. An output schema is absent, but the description's 'full detail' plus the view parameter documentation is sufficient for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds a small but real semantic cue by explaining that residence_id can come from either a booli.se/bostad/<id> URL or a search result's residence_id field, which helps the agent source the value correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: 'Full detail for one property by its Booli residence id.' It clearly identifies the lookup key and distinguishes this from the sibling search/stats/health tools, which do different jobs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It tells the agent the precondition for use: the agent must already have a Booli residence id, either from a URL or a search result. It also clarifies that the tool works for both active and sold properties. It does not explicitly name alternative tools for cases where no id is available, but the context and sibling names make this reasonably clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
booli_healthcheckVerify the fetchproxy bridge end-to-endARead-onlyIdempotent
Round-trips a small public www.booli.se URL (/graphql) through the fetchproxy bridge and returns diagnostics: the bridge's role (host/peer/null), port, version, the extension link (linked / pair pending / not attached / never answered), the elapsed round-trip time, and a plain-English hint distinguishing 'bridge never came up' from 'extension not connected' from 'real www.booli.se-side problem'. Read-only, no auth required. Call this when a real tool fails and you want to know which hop broke.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description says 'Read-only, no auth required', which adds useful safety/auth context beyond the readOnlyHint and idempotentHint annotations. It also discloses the network round-trip behavior and the specific diagnostics returned, giving the agent a clear model of what the call will and will not do.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single detailed sentence followed by a usage directive. The enumerated diagnostics are useful rather than padded, and the 'Call this when...' guidance is placed at the end. It is slightly long but every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no parameters, no output schema, and annotations already covering read-only and idempotency, the description carries the full explanatory burden and meets it. It explains the purpose, the behavior, the expected diagnostics, authentication, and the concrete failure scenario in which the tool should be used.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the schema is empty, so the baseline of 4 applies. The description adds no parameter detail, but none is needed because there is nothing to configure.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action and resource: round-tripping a small public www.booli.se URL through the fetchproxy bridge and returning diagnostics. It clearly differentiates the tool from the search/get sibling tools, which target listings and areas rather than bridge health.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states an explicit trigger: 'Call this when a real tool fails and you want to know which hop broke.' It does not name when-not-to-use or alternative tools, but the healthcheck's role is sufficiently distinct from the sibling search tools that the guidance is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
booli_market_statsBooli sold-price market statisticsARead-only
Aggregate sold-price statistics (median/average final price, price per m², average over/under-asking %) for an area on booli.se. Takes the same scope and filters as booli_search_sold, over one page of sold results. Check sample_size before trusting a thin median. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 1-based page (default 1). | |
| sort | No | Sort key (default: soldDate — most recent sales first with ascending false). | |
| view | No | Response shape: "compact" (default) drops fields the response already carries elsewhere; "full" returns every field this server understands. compact returns the slim PropertySummary/detail projection; "full" returns Booli's whole GraphQL node. | |
| area_id | No | Booli area id from booli_search_areas. Provide this OR `location`. | |
| location | No | Free-text place name (e.g. "Nacka", "Södermalm") resolved to its top Booli area. Ignored when `area_id` is set. | |
| ascending | No | Sort ascending (default false). | |
| max_rooms | No | ||
| min_rooms | No | ||
| object_type | No | Property type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark. | |
| max_plot_area | No | m² | |
| max_sold_date | No | Latest sold date, YYYYMMDD. | |
| min_plot_area | No | m² | |
| min_sold_date | No | Earliest sold date, YYYYMMDD (e.g. "20240101"). | |
| max_sold_price | No | SEK | |
| min_sold_price | No | SEK | |
| max_living_area | No | m² | |
| min_living_area | No | m² | |
| max_sold_sqm_price | No | SEK/m² | |
| min_sold_sqm_price | No | SEK/m² | |
| is_new_construction | No | true = only new production; false = exclude new production. | |
| max_construction_year | No | ||
| min_construction_year | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark readOnlyHint=true, so the description's 'Read-only' is redundant. However, it adds valuable behavioral context: the tool operates over exactly one page of results and warns about sample_size affecting median reliability. These are not derivable from annotations or schema, so they meaningfully disclose behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences, front-loads the purpose, and includes the key caveat about sample_size. Every sentence carries meaning with no filler or repetition of schema details. It is appropriately concise for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 22 parameters, no output schema, and is a read-only aggregation, the description is sufficient. It explains what it returns, its relationship to booli_search_sold, and a practical trust caveat. It does not detail return structure or pagination beyond one page, but that is reasonably implied. For an aggregation tool with this complexity, it is well-rounded.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is high (82%), so the schema already documents most parameters. The description adds no per-parameter detail, but it references that the tool shares the same filters as booli_search_sold, which implies parameter reuse. Since the schema covers the parameters, a baseline of 3 is appropriate; the description adds marginal value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Aggregate') and a clear resource ('sold-price statistics'), and explicitly lists the derived metrics (median/average final price, price per m², average over/under-asking %). It also differentiates from sibling tools by referencing booli_search_sold as the scope basis, so an agent can distinguish it from listing retrieval.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the tool takes 'the same scope and filters as booli_search_sold', giving clear context on when to use it (for aggregate stats on a page of sold results). It also adds a practical tip ('Check sample_size before trusting a thin median'). It does not explicitly name alternatives or exclusions, but the reference to booli_search_sold implicitly routes away from listing tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
booli_search_areasResolve a Booli areaARead-onlyIdempotent
Resolve a place name to Booli areas — municipalities, districts, streets — each with its area_id to pass as area_id into booli_search_listings / booli_search_sold. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (default 10). | |
| query | Yes | Place-name search string (e.g. "Nacka", "Södermalm"). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already cover safety with readOnlyHint, idempotentHint, and openWorldHint, lowering the bar. The description adds some behavioral context by specifying that it returns municipalities, districts, and streets each with an `area_id`, but 'Read-only' merely repeats what readOnlyHint already declares. It does not disclose ambiguity handling, multiple match behavior, or other runtime quirks.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core sentence is dense, front-loaded, and contains the essential purpose, output types, and downstream usage in one line. The trailing 'Read-only.' is redundant with the annotations but is harmless; the overall definition is compact and efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter resolver with safe annotations, the description is largely complete: it explains the input, the output types, and how the output is consumed by sibling tools. Because there is no output schema, it would be slightly stronger to state what happens on no match or how many areas may be returned, but the essential calling context is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already explains both `query` and `limit`. The description reinforces that `query` is a place name and that the result carries `area_id`, but it does not add meaningful parameter-level detail beyond what the input schema provides, so the baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Resolve') plus a clear resource ('place name to Booli areas') and names the concrete output types: municipalities, districts, streets. It also differentiates the tool by stating that the resulting `area_id` feeds into booli_search_listings / booli_search_sold, so an agent can distinguish it from its siblings without opening their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context for when to use the tool: resolving a place name before searching listings or sold data via the returned `area_id`. It names the downstream tools, which implies the intended workflow, but it does not explicitly state when not to use this tool or name a direct alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
booli_search_listingsSearch Booli for-sale listingsARead-only
Search active for-sale property listings on booli.se. Scope by area_id (from booli_search_areas) or a free-text location, and filter by price, rooms, living area, plot, object type, construction year. Paginated by page; check total_count/pages. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 1-based page (default 1). | |
| sort | No | Sort key (default: newest published). | |
| view | No | Response shape: "compact" (default) drops fields the response already carries elsewhere; "full" returns every field this server understands. compact returns the slim PropertySummary/detail projection; "full" returns Booli's whole GraphQL node. | |
| area_id | No | Booli area id from booli_search_areas. Provide this OR `location`. | |
| location | No | Free-text place name (e.g. "Nacka", "Södermalm") resolved to its top Booli area. Ignored when `area_id` is set. | |
| ascending | No | Sort ascending (default false). | |
| max_rooms | No | ||
| min_rooms | No | ||
| object_type | No | Property type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark. | |
| max_plot_area | No | m² | |
| min_plot_area | No | m² | |
| max_list_price | No | SEK | |
| min_list_price | No | SEK | |
| max_living_area | No | m² | |
| min_living_area | No | m² | |
| max_list_sqm_price | No | SEK/m² | |
| min_list_sqm_price | No | SEK/m² | |
| is_new_construction | No | true = only new production; false = exclude new production. | |
| max_construction_year | No | ||
| min_construction_year | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, and the description reinforces this with 'Read-only.' It adds behavioral context beyond annotations by describing pagination ('Paginated by `page`; check `total_count`/`pages`') and the scoping rule ('area_id ... OR location'). No contradictions; the description complements the annotations with operational detail.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no wasted words. The purpose is stated first, then scoping, then filters, then pagination. Every clause earns its place. The structure is front-loaded with the most important information and reads naturally.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 20-parameter search tool with no output schema, the description covers the core behaviors: what it searches, how to scope, what filters exist, and how pagination works. It references a sibling for area_id resolution. It doesn't mention authentication or rate limits, but those are not essential for selection. The description is sufficient for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 80%, so the baseline is 3. The description adds value by explaining the relationship between area_id and location (location ignored when area_id is set), and by grouping filters by category (price, rooms, living area, etc.). It also clarifies that area_id comes from booli_search_areas, which is not in the schema. This goes beyond the schema's per-parameter descriptions, warranting a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb+resource: 'Search active for-sale property listings on booli.se.' It distinguishes itself from siblings by the 'active for-sale' qualifier, which sets it apart from booli_search_sold (sold listings), booli_get_listing (single listing), and the others. An agent can tell exactly what this tool does and when to reach for it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear context: it's for active for-sale listings, and it even references booli_search_areas for obtaining area_id. It implies the 'when' (when you need active listings) but does not explicitly state exclusions like 'use booli_search_sold for sold listings.' However, the 'active' qualifier and the sibling names make the usage boundary evident, so it's clear enough without being exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
booli_search_soldSearch Booli sold listings (slutpriser)ARead-only
Search sold properties (slutpriser) on booli.se with the achieved final price and over/under-asking % — the comparables for valuation. Scope by area_id or free-text location, filter by sold price, sold date, rooms, area, object type. Paginated by page. Read-only.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 1-based page (default 1). | |
| sort | No | Sort key (default: soldDate — most recent sales first with ascending false). | |
| view | No | Response shape: "compact" (default) drops fields the response already carries elsewhere; "full" returns every field this server understands. compact returns the slim PropertySummary/detail projection; "full" returns Booli's whole GraphQL node. | |
| area_id | No | Booli area id from booli_search_areas. Provide this OR `location`. | |
| location | No | Free-text place name (e.g. "Nacka", "Södermalm") resolved to its top Booli area. Ignored when `area_id` is set. | |
| ascending | No | Sort ascending (default false). | |
| max_rooms | No | ||
| min_rooms | No | ||
| object_type | No | Property type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark. | |
| max_plot_area | No | m² | |
| max_sold_date | No | Latest sold date, YYYYMMDD. | |
| min_plot_area | No | m² | |
| min_sold_date | No | Earliest sold date, YYYYMMDD (e.g. "20240101"). | |
| max_sold_price | No | SEK | |
| min_sold_price | No | SEK | |
| max_living_area | No | m² | |
| min_living_area | No | m² | |
| max_sold_sqm_price | No | SEK/m² | |
| min_sold_sqm_price | No | SEK/m² | |
| is_new_construction | No | true = only new production; false = exclude new production. | |
| max_construction_year | No | ||
| min_construction_year | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint and openWorldHint, and the description reinforces safety with 'Read-only.' It adds useful behavioral context beyond annotations by specifying the result includes achieved final price and over/under-asking %, plus pagination by page. No contradictions with annotations are present.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded with the core purpose before filter details. It earns its place overall, though 'Read-only' repeats the annotation and the single long sentence could be split for slightly easier parsing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite 22 optional parameters and no output schema, the description plus schema covers scope selection, filter dimensions, pagination, and key return fields. An agent can determine how to invoke the tool, though deeper output-shape details are left unspecified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is high at 82%, so the baseline is 3. The description adds a helpful high-level grouping of scope by area_id/location and filter categories, but it does not add substantial new parameter meaning beyond what the schema already documents for the remaining parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: searching sold properties (slutpriser) on booli.se. It also adds distinguishing scope by mentioning achieved final price and over/under-asking %, positioning it as the comparables tool next to siblings like booli_search_listings and booli_market_stats.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'the comparables for valuation' gives clear context for when this tool is the right choice. It does not explicitly name alternatives or exclusion conditions, but the sold-property framing strongly separates it from active listing or stats siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v2.1.3- Changed
booli_market_stats2 fields changed- changed
Input schema / properties / sort / descriptionPrevious value: -"Sort key (default: newest published)."New value: +"Sort key (default: soldDate — most recent sales first with ascending false)." - changed
Input schema / properties / sort / enumPrevious value: -[ - "published", - "listPrice", - "listSqmPrice", - "rooms", - "livingArea", - "rent", - "plotArea" -]New value: +[ + "published", + "listPrice", + "listSqmPrice", + "rooms", + "livingArea", + "rent", + "plotArea", + "soldDate", + "soldPrice" +]
- Changed
booli_search_sold2 fields changed- changed
Input schema / properties / sort / descriptionPrevious value: -"Sort key (default: newest published)."New value: +"Sort key (default: soldDate — most recent sales first with ascending false)." - changed
Input schema / properties / sort / enumPrevious value: -[ - "published", - "listPrice", - "listSqmPrice", - "rooms", - "livingArea", - "rent", - "plotArea" -]New value: +[ + "published", + "listPrice", + "listSqmPrice", + "rooms", + "livingArea", + "rent", + "plotArea", + "soldDate", + "soldPrice" +]
6 tool updates
v2.0.0- Changed
booli_get_listing1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
booli_healthcheck1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
booli_market_stats1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
booli_search_areas1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
booli_search_listings1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
- Changed
booli_search_sold1 field changed- changed
Input schema / $schemaPrevious value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
4 tool updates
v1.3.1- Changed
booli_get_listing2 fields changed- removed
Input schema / properties / compactRemoved value: -{ - "description": "Return a slim summary instead of the full raw record (default false).", - "type": "boolean" -} - added
Input schema / properties / viewAdded value: +{ + "description": "Response shape: \"compact\" (default) drops fields the response already carries elsewhere; \"full\" returns every field this server understands. compact returns the slim PropertySummary/detail projection; \"full\" returns Booli's whole GraphQL node.", + "enum": [ + "compact", + "full" + ], + "type": "string" +}
- Changed
booli_market_stats2 fields changed- removed
Input schema / properties / compactRemoved value: -{ - "description": "Return slim summary records (default true). Set false for full raw fields.", - "type": "boolean" -} - added
Input schema / properties / viewAdded value: +{ + "description": "Response shape: \"compact\" (default) drops fields the response already carries elsewhere; \"full\" returns every field this server understands. compact returns the slim PropertySummary/detail projection; \"full\" returns Booli's whole GraphQL node.", + "enum": [ + "compact", + "full" + ], + "type": "string" +}
- Changed
booli_search_listings2 fields changed- removed
Input schema / properties / compactRemoved value: -{ - "description": "Return slim summary records (default true). Set false for full raw fields.", - "type": "boolean" -} - added
Input schema / properties / viewAdded value: +{ + "description": "Response shape: \"compact\" (default) drops fields the response already carries elsewhere; \"full\" returns every field this server understands. compact returns the slim PropertySummary/detail projection; \"full\" returns Booli's whole GraphQL node.", + "enum": [ + "compact", + "full" + ], + "type": "string" +}
- Changed
booli_search_sold2 fields changed- removed
Input schema / properties / compactRemoved value: -{ - "description": "Return slim summary records (default true). Set false for full raw fields.", - "type": "boolean" -} - added
Input schema / properties / viewAdded value: +{ + "description": "Response shape: \"compact\" (default) drops fields the response already carries elsewhere; \"full\" returns every field this server understands. compact returns the slim PropertySummary/detail projection; \"full\" returns Booli's whole GraphQL node.", + "enum": [ + "compact", + "full" + ], + "type": "string" +}
6 tool updates
v1.0.0- Changed
booli_get_listing3 fields changed- removed
Input schema / properties / booli_idRemoved value: -{ - "description": "The listing's Booli id (e.g. \"1579812\").", - "type": "string" -} - added
Input schema / properties / residence_idAdded value: +{ + "description": "The property's residence id (e.g. \"4370936\" from /bostad/4370936).", + "type": "string" +} - changed
Input schema / requiredPrevious value: -[ - "booli_id" -]New value: +[ + "residence_id" +]
- Removed
booli_get_sold - Changed
booli_market_stats13 fields changed- changed
Input schema / properties / area_id / descriptionPrevious value: -"Booli area id(s) from booli_search_areas, comma-separated for several (e.g. \"76,16\")."New value: +"Booli area id from booli_search_areas. Provide this OR `location`." - added
Input schema / properties / ascendingAdded value: +{ + "description": "Sort ascending (default false).", + "type": "boolean" +} - removed
Input schema / properties / bboxRemoved value: -{ - "description": "Bounding box \"lat_lo,lng_lo,lat_hi,lng_hi\" (SW then NE corner).", - "type": "string" -} - removed
Input schema / properties / centerRemoved value: -{ - "description": "Coordinate \"lat,lng\" (e.g. \"59.34674,18.0603\"); use with `dim`.", - "type": "string" -} - removed
Input schema / properties / dimRemoved value: -{ - "description": "Rectangle size in metres \"w,h\" (e.g. \"400,500\"), used with `center`.", - "type": "string" -} - removed
Input schema / properties / limitRemoved value: -{ - "description": "Default 30, max 100.", - "maximum": 100, - "minimum": 1, - "type": "integer" -} - added
Input schema / properties / locationAdded value: +{ + "description": "Free-text place name (e.g. \"Nacka\", \"Södermalm\") resolved to its top Booli area. Ignored when `area_id` is set.", + "type": "string" +} - removed
Input schema / properties / max_rentRemoved value: -{ - "description": "SEK/month", - "minimum": 0, - "type": "number" -} - changed
Input schema / properties / object_type / descriptionPrevious value: -"Property type(s), comma-separated, from: villa, lägenhet, gård, tomt-mark, fritidshus, parhus, radhus, kedjehus."New value: +"Property type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark." - removed
Input schema / properties / offsetRemoved value: -{ - "description": "Pagination offset.", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" -} - added
Input schema / properties / pageAdded value: +{ + "description": "1-based page (default 1).", + "maximum": 9007199254740991, + "minimum": 1, + "type": "integer" +} - removed
Input schema / properties / qRemoved value: -{ - "description": "Free-text area search (e.g. \"Nacka\", \"Södermalm\"). One of q / area_id / center / bbox scopes the search.", - "type": "string" -} - added
Input schema / properties / sortAdded value: +{ + "description": "Sort key (default: newest published).", + "enum": [ + "published", + "listPrice", + "listSqmPrice", + "rooms", + "livingArea", + "rent", + "plotArea" + ], + "type": "string" +}
- Changed
booli_search_areas8 fields changed- removed
Input schema / properties / latRemoved value: -{ - "description": "Latitude; use together with `lng`.", - "type": "number" -} - changed
Input schema / properties / limit / descriptionPrevious value: -"Default 10, max 50."New value: +"Max results (default 10)." - removed
Input schema / properties / lngRemoved value: -{ - "description": "Longitude; use together with `lat`.", - "type": "number" -} - removed
Input schema / properties / only_with_listingsRemoved value: -{ - "description": "Only return areas that currently have listings for sale.", - "type": "boolean" -} - removed
Input schema / properties / only_with_soldRemoved value: -{ - "description": "Only return areas that have sold listings.", - "type": "boolean" -} - removed
Input schema / properties / qRemoved value: -{ - "description": "Place-name search string (e.g. \"Nacka\").", - "type": "string" -} - added
Input schema / properties / queryAdded value: +{ + "description": "Place-name search string (e.g. \"Nacka\", \"Södermalm\").", + "type": "string" +} - added
Input schema / requiredAdded value: +[ + "query" +]
- Changed
booli_search_listings13 fields changed- changed
Input schema / properties / area_id / descriptionPrevious value: -"Booli area id(s) from booli_search_areas, comma-separated for several (e.g. \"76,16\")."New value: +"Booli area id from booli_search_areas. Provide this OR `location`." - added
Input schema / properties / ascendingAdded value: +{ + "description": "Sort ascending (default false).", + "type": "boolean" +} - removed
Input schema / properties / bboxRemoved value: -{ - "description": "Bounding box \"lat_lo,lng_lo,lat_hi,lng_hi\" (SW then NE corner).", - "type": "string" -} - removed
Input schema / properties / centerRemoved value: -{ - "description": "Coordinate \"lat,lng\" (e.g. \"59.34674,18.0603\"); use with `dim`.", - "type": "string" -} - removed
Input schema / properties / dimRemoved value: -{ - "description": "Rectangle size in metres \"w,h\" (e.g. \"400,500\"), used with `center`.", - "type": "string" -} - removed
Input schema / properties / limitRemoved value: -{ - "description": "Default 30, max 100.", - "maximum": 100, - "minimum": 1, - "type": "integer" -} - added
Input schema / properties / locationAdded value: +{ + "description": "Free-text place name (e.g. \"Nacka\", \"Södermalm\") resolved to its top Booli area. Ignored when `area_id` is set.", + "type": "string" +} - removed
Input schema / properties / max_rentRemoved value: -{ - "description": "SEK/month", - "minimum": 0, - "type": "number" -} - changed
Input schema / properties / object_type / descriptionPrevious value: -"Property type(s), comma-separated, from: villa, lägenhet, gård, tomt-mark, fritidshus, parhus, radhus, kedjehus."New value: +"Property type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark." - removed
Input schema / properties / offsetRemoved value: -{ - "description": "Pagination offset.", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" -} - added
Input schema / properties / pageAdded value: +{ + "description": "1-based page (default 1).", + "maximum": 9007199254740991, + "minimum": 1, + "type": "integer" +} - removed
Input schema / properties / qRemoved value: -{ - "description": "Free-text area search (e.g. \"Nacka\", \"Södermalm\"). One of q / area_id / center / bbox scopes the search.", - "type": "string" -} - added
Input schema / properties / sortAdded value: +{ + "description": "Sort key (default: newest published).", + "enum": [ + "published", + "listPrice", + "listSqmPrice", + "rooms", + "livingArea", + "rent", + "plotArea" + ], + "type": "string" +}
- Changed
booli_search_sold13 fields changed- changed
Input schema / properties / area_id / descriptionPrevious value: -"Booli area id(s) from booli_search_areas, comma-separated for several (e.g. \"76,16\")."New value: +"Booli area id from booli_search_areas. Provide this OR `location`." - added
Input schema / properties / ascendingAdded value: +{ + "description": "Sort ascending (default false).", + "type": "boolean" +} - removed
Input schema / properties / bboxRemoved value: -{ - "description": "Bounding box \"lat_lo,lng_lo,lat_hi,lng_hi\" (SW then NE corner).", - "type": "string" -} - removed
Input schema / properties / centerRemoved value: -{ - "description": "Coordinate \"lat,lng\" (e.g. \"59.34674,18.0603\"); use with `dim`.", - "type": "string" -} - removed
Input schema / properties / dimRemoved value: -{ - "description": "Rectangle size in metres \"w,h\" (e.g. \"400,500\"), used with `center`.", - "type": "string" -} - removed
Input schema / properties / limitRemoved value: -{ - "description": "Default 30, max 100.", - "maximum": 100, - "minimum": 1, - "type": "integer" -} - added
Input schema / properties / locationAdded value: +{ + "description": "Free-text place name (e.g. \"Nacka\", \"Södermalm\") resolved to its top Booli area. Ignored when `area_id` is set.", + "type": "string" +} - removed
Input schema / properties / max_rentRemoved value: -{ - "description": "SEK/month", - "minimum": 0, - "type": "number" -} - changed
Input schema / properties / object_type / descriptionPrevious value: -"Property type(s), comma-separated, from: villa, lägenhet, gård, tomt-mark, fritidshus, parhus, radhus, kedjehus."New value: +"Property type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark." - removed
Input schema / properties / offsetRemoved value: -{ - "description": "Pagination offset.", - "maximum": 9007199254740991, - "minimum": 0, - "type": "integer" -} - added
Input schema / properties / pageAdded value: +{ + "description": "1-based page (default 1).", + "maximum": 9007199254740991, + "minimum": 1, + "type": "integer" +} - removed
Input schema / properties / qRemoved value: -{ - "description": "Free-text area search (e.g. \"Nacka\", \"Södermalm\"). One of q / area_id / center / bbox scopes the search.", - "type": "string" -} - added
Input schema / properties / sortAdded value: +{ + "description": "Sort key (default: newest published).", + "enum": [ + "published", + "listPrice", + "listSqmPrice", + "rooms", + "livingArea", + "rent", + "plotArea" + ], + "type": "string" +}
7 tool updates
v0.0.0- First observed
booli_get_listing - First observed
booli_get_sold - First observed
booli_healthcheck - First observed
booli_market_stats - First observed
booli_search_areas - First observed
booli_search_listings - First observed
booli_search_sold
TDQS
Scored across 6 tools
Each tool has a clearly distinct purpose: detail lookup, active search, sold search, aggregate stats, area resolution, and diagnostics. The only potential overlap between booli_market_stats and booli_search_sold is clearly separated as aggregate versus individual results.
All tools share the booli_ prefix and use lowercase snake_case with a verb or descriptive noun. Minor deviations like booli_healthcheck and booli_market_stats not following the strict verb_noun form are slight but do not harm predictability.
Six tools is a well-scoped count for a real-estate data server. Each tool earns its place and there is no redundant bloat or sparse coverage.
The surface covers the core read-only domain well: resolving areas, searching active listings, searching sold listings, retrieving listing details, computing market stats, and diagnosing connectivity. No significant gaps are apparent for the stated purpose.
Maintenance
Related MCP Connectors
Redfin listings, sale-comps, and neighborhood market data via natural-language queries.
Pull property listings, prices, and details from real-estate sites as structured JSON.
Booking.com stays by destination and dates, and full property details, as structured JSON.
Zillow for-sale, for-rent and sold listings, and full property details, as structured JSON.
Related MCP Servers
- FlicenseBqualityNot gradedmaintenanceEnables AI assistants to search and analyze Swedish real estate data from Booli.se using natural language queries. Supports property searches with comprehensive filtering options and location discovery through GraphQL API integration.31-
- AlicenseCqualityDmaintenanceEnables access to Idealista API for searching and retrieving property listings across Spain, Portugal, and Italy. Supports various property types including homes, apartments, garages, commercial properties, offices, and land with detailed filtering options.143MIT
- AlicenseNot gradedqualityFmaintenanceProvides real-time access to Zillow real estate data, enabling property search, details, Zestimates, market trends, and mortgage calculations via natural language.4 npm48MIT
- AlicenseAqualityCmaintenanceEnables searching Korean apartment listings, market prices, and recent transactions via Naver Real Estate through natural language.6MIT