Skip to main content
Glama
chrischall

booli-mcp

by chrischall

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 ContextMint Bridge browser 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

  1. Install ContextMint Bridge from its releases page — Chrome: download the chrome zip, unzip it, and load it unpacked at chrome://extensions (Developer mode). Safari isn't available yet (it will ship inside the ContextMint app, which has no public download), so use Chrome for now. Keep a www.booli.se tab open.

    ContextMint Bridge is the fetchproxy browser extension under its new name, from the same maintainer — fetchproxy's own README points to it. Its source is public at nullnet-app/contextmint-bridge: build it yourself, or check a release zip against the .sha256 file published beside it (shasum -a 256 -c contextmint-bridge-chrome-<version>.zip.sha256).

  2. On the first request, approve the one-time pairing prompt in ContextMint Bridge.

  3. Run booli_healthcheck to confirm the path is working. Its transport field says which leg served the probe (direct or fetchproxy) and, once the bridge exists, bridge.session_state says whether the extension is linked, pair_pending (approve the pair code it names), or extension_disconnected.

Install

// mcp config
{
  "mcpServers": {
    "booli": {
      "command": "npx",
      "args": ["-y", "@chrischall/booli-mcp"]
    }
  }
}

Tools

Tool

What it does

booli_search_areas

Resolve a place name to Booli area ids

booli_search_listings

Search active for-sale listings by area + filters

booli_get_listing

Full detail for one property (active or sold) by residence id

booli_search_sold

Search sold listings (slutpriser) with final prices

booli_market_stats

Median/average sold-price statistics for an area

booli_healthcheck

Probe the data path and report transport (direct / fetchproxy, the BOOLI_TRANSPORT mode) and, once the bridge is up, bridge (role, port, extension link session_state, pending pair code) with a next-step hint

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 bundle

License

MIT

Available Tools

6 tools
booli_get_listingGet a Booli propertyA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
viewNoResponse 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_idYesThe property's residence id (e.g. "4370936" from /bostad/4370936).

TDQS

A4/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint, so the safety and repeatability profile is fully covered and "Read-only" in the description is largely redundant. The one genuinely additive behavioral fact is the active/sold scope; nothing is said about missing-id errors, rate limits, or data freshness. With annotations carrying the burden, a 3 is appropriate.

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

Conciseness5/5

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

Two tight sentences, front-loaded with what is returned, zero filler; the final "Read-only" is the only slightly redundant clause and costs almost nothing.

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?

No output schema exists, but the description plus the schema's `view` documentation adequately convey the returned shape (compact projection vs full GraphQL node). Naming the id source (URL or search result) closes the main integration gap; only error behavior for an unknown id is left uncovered.

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?

Schema coverage is 100% and both parameters are documented in the schema, including the compact/full enum and id example. The description's id guidance (booli.se/bostad/<id>, residence_id from search) largely restates the schema example, and it says nothing about the `view` parameter. Baseline 3 when the schema does the work.

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?

"Full detail for one property by its Booli residence id" is a specific verb+resource plus the identifier, and the contrast with the search siblings (one vs many) is implicit in the phrasing. An agent can tell this is the single-record lookup rather than a search.

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

Usage Guidelines4/5

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

It states when this applies: it accepts an id from a URL or a search result, and "works for both active and sold properties" removes the ambiguity of whether a separate sold-property lookup is needed. It stops short of naming alternatives or stating prerequisites (e.g. needing an id in hand rather than a query).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

booli_healthcheckVerify the ContextMint Bridge connection end-to-endA
Read-onlyIdempotent

Round-trips a small public www.booli.se URL (/graphql) through ContextMint Bridge (your signed-in browser tab) 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 'this browser can't serve a capability' 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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.8/5.0
Behavior5/5

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

Goes well beyond the annotations by enumerating the returned diagnostics (bridge role, port, version, extension link state, elapsed time) and enumerating the failure classes the hint distinguishes (bridge never came up / extension not connected / browser can't serve capability / server-side problem). It also confirms 'no auth required'. This is real behavioral context an agent cannot infer from readOnlyHint/idempotentHint alone.

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

Conciseness4/5

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

A single dense sentence plus a short routing instruction, front-loaded with the action and ending with the failure-mode enumeration. The list of diagnostics is long but each item earns its place; the only minor cost is one very overloaded sentence.

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

Completeness5/5

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

With no output schema, the description carries the full burden of explaining what comes back, and it does so comprehensively – listing every diagnostic field and the interpretive hint. Nothing needed to call or interpret this tool is missing.

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

Parameters4/5

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

The tool takes zero parameters, so the baseline is 4. There is nothing for the description to disambiguate beyond confirming the call is parameter-free, which it implicitly does by describing a self-contained round-trip.

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?

States a specific action (round-trips a public booli.se URL through ContextMint Bridge), the exact resource (/graphql), and the nature of the result (diagnostics). It is unmistakably a health/diagnostic tool, distinct from the listing/search/stats siblings, without opening any schema.

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

Usage Guidelines5/5

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

Explicitly says when to call it: 'Call this when a real tool fails and you want to know which hop broke.' That is a clear trigger condition and implicitly positions it as a fallback to the other booli_* tools.

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 statisticsA
Read-onlyIdempotent

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, computed over ONE page of sold results (most recent first by default) — page/pages say which, and total_count is the whole matching set, not the sample. sample_size is the rows on the page; sold_price_count / price_per_sqm_count / price_change_count are the rows that fed each metric. Check them before trusting a thin median. Read-only.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-based page (default 1).
sortNoSort key (default: soldDate — most recent sales first with ascending false).
viewNoResponse 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_idNoBooli area id from booli_search_areas. Provide this OR `location`.
locationNoFree-text place name (e.g. "Nacka", "Södermalm") resolved to its top Booli area. Ignored when `area_id` is set.
ascendingNoSort ascending (default false).
max_roomsNo
min_roomsNo
object_typeNoProperty type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark.
max_plot_areaNom²
max_sold_dateNoLatest sold date, YYYYMMDD.
min_plot_areaNom²
min_sold_dateNoEarliest sold date, YYYYMMDD (e.g. "20240101").
max_sold_priceNoSEK
min_sold_priceNoSEK
max_living_areaNom²
min_living_areaNom²
max_sold_sqm_priceNoSEK/m²
min_sold_sqm_priceNoSEK/m²
is_new_constructionNotrue = only new production; false = exclude new production.
max_construction_yearNo
min_construction_yearNo

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already establish read-only/idempotent/open-world behavior, so the bar is lower, and the description adds real value: it discloses that metrics are computed over ONE page of results, distinguishes total_count from sample_size, and warns that thin per-metric counts undermine a median. Those sampling semantics are genuine behavioral context beyond the annotations, though auth/rate-limit traits are not addressed.

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

Conciseness4/5

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

The purpose is front-loaded and each sentence carries information (sample reliability, total vs. sample distinction). The mid-sentence em-dash construction mixing input and output field names makes it slightly dense to parse, but nothing is redundant.

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?

With no output schema and 22 parameters, the description does substantial work by naming the returned metric fields, the row counts behind each metric, and the total-vs-sample distinction — compensating for the missing return-value spec. Some filter semantics still lean entirely on the schema, but nothing critical to calling it correctly is absent.

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?

Schema coverage is high (82%), so the schema already documents most of the 22 parameters, setting the baseline at 3. The description adds only a little param-level meaning ('page'/'pages' say which page — though no 'pages' param exists), and the field names it explains (sample_size, sold_price_count) are outputs rather than inputs.

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?

States a precise verb and resource — 'Aggregate sold-price statistics (median/average final price, price per m², average over/under-asking %)' — and explicitly anchors it to a sibling ('Takes the same scope and filters as booli_search_sold'). An agent can distinguish this aggregation tool from the listing-returning booli_search_sold without opening either schema.

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

Usage Guidelines4/5

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

Clearly frames the tool as the aggregate counterpart to booli_search_sold, so the choice between them is inferable (stats vs. raw listings). It lacks an explicit when-to-use/when-not statement or a named alternative for edge cases, keeping it just below the top tier.

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 areaA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMax results (default 10).
queryYesPlace-name search string (e.g. "Nacka", "Södermalm").

TDQS

A4.2/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, destructiveHint=false, so 'Read-only' in the description is largely redundant. However, with no output schema, the description adds real value by disclosing the return shape (each area carries an `area_id`), which is the key behavioral fact an agent needs.

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

Conciseness5/5

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

A single sentence, front-loaded with the verb and resource, then the downstream handoff, then a safety tag. Nothing is wasted and no clause is buried.

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?

For a two-parameter lookup with no output schema, the description covers purpose, downstream use, and return shape, which is what an agent needs to call it correctly. Minor gaps remain (result ordering, ambiguity handling for multi-match place names), but nothing blocking.

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?

Schema description coverage is 100%, so both `query` and `limit` are already documented in the schema (including the default of 10). The description adds no syntax, format, or matching-semantics detail beyond the schema, so the baseline of 3 applies.

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?

States a specific verb and resource ('Resolve a place name to Booli areas') and enumerates the entity types returned (municipalities, districts, streets). It also names the sibling tools it feeds (booli_search_listings / booli_search_sold), so an agent can place it in the workflow without opening a schema.

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

Usage Guidelines4/5

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

The description makes the usage contract explicit: call this first to turn a place name into an `area_id`, then pass that id into booli_search_listings / booli_search_sold. It gives clear context but no explicit 'do not use this for X' exclusion (e.g. resolving non-place inputs).

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 listingsA
Read-onlyIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-based page (default 1).
sortNoSort key (default: newest published).
viewNoResponse 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_idNoBooli area id from booli_search_areas. Provide this OR `location`.
locationNoFree-text place name (e.g. "Nacka", "Södermalm") resolved to its top Booli area. Ignored when `area_id` is set.
ascendingNoSort ascending (default false).
max_roomsNo
min_roomsNo
object_typeNoProperty type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark.
max_plot_areaNom²
min_plot_areaNom²
max_list_priceNoSEK
min_list_priceNoSEK
max_living_areaNom²
min_living_areaNom²
max_list_sqm_priceNoSEK/m²
min_list_sqm_priceNoSEK/m²
is_new_constructionNotrue = only new production; false = exclude new production.
max_construction_yearNo
min_construction_yearNo

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint and idempotentHint, so safety is covered; the description still adds value by disclosing pagination behavior and the total_count/pages fields to inspect in the response, which matters because there is no output schema. 'Read-only' is redundant with the annotation but harmless.

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

Conciseness4/5

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

Roughly three sentences, front-loaded with the resource and scope, then filters, then pagination. Nearly every clause earns its place; only the trailing 'Read-only' is filler given the annotation already states it.

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?

For a 20-parameter, zero-required search tool with no output schema, the description covers scope, filter families, pagination, and response count fields. Sort/view semantics and input ranges are left to the schema, which is acceptable, but a note on defaults or result limits would complete it.

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?

Schema description coverage is 80%, so the schema already documents nearly every parameter, including the area_id-vs-location precedence and enum values. The description adds only a grouped summary of filter categories (price, rooms, living area, plot, object type, construction year), which is the baseline for a well-covered schema.

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?

States a specific verb and resource with scope: 'Search active for-sale property listings on booli.se.' The word 'active' plus 'for-sale' implicitly separates it from booli_search_sold, and it names booli_search_areas as the source of area_id, so an agent can route correctly without opening schemas.

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

Usage Guidelines4/5

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

Gives clear usage context: scope by area_id or free-text location, filter by the listed dimensions, paginate by page. It routes the agent to booli_search_areas for area IDs but never states when to prefer a sibling such as booli_market_stats or booli_get_listing; there are no explicit exclusions.

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)A
Read-onlyIdempotent

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-based page (default 1).
sortNoSort key (default: soldDate — most recent sales first with ascending false).
viewNoResponse 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_idNoBooli area id from booli_search_areas. Provide this OR `location`.
locationNoFree-text place name (e.g. "Nacka", "Södermalm") resolved to its top Booli area. Ignored when `area_id` is set.
ascendingNoSort ascending (default false).
max_roomsNo
min_roomsNo
object_typeNoProperty type(s), comma-separated, from: Lägenhet, Villa, Kedjehus-Parhus-Radhus, Fritidshus, Gård, Tomt/Mark.
max_plot_areaNom²
max_sold_dateNoLatest sold date, YYYYMMDD.
min_plot_areaNom²
min_sold_dateNoEarliest sold date, YYYYMMDD (e.g. "20240101").
max_sold_priceNoSEK
min_sold_priceNoSEK
max_living_areaNom²
min_living_areaNom²
max_sold_sqm_priceNoSEK/m²
min_sold_sqm_priceNoSEK/m²
is_new_constructionNotrue = only new production; false = exclude new production.
max_construction_yearNo
min_construction_yearNo

TDQS

A3.7/5.0
Behavior3/5

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

Annotations already declare readOnlyHint, idempotentHint, openWorldHint and destructiveHint=false, so the description's 'Read-only' adds nothing new. It does contribute the result content (final price plus over/under-asking %) and pagination behaviour, but says nothing about external-API rate limits, auth, or completeness guarantees for an open-world scraping-style source.

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

Conciseness4/5

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

Front-loaded with the resource and its differentiating output, followed by scoping, filtering, pagination and the read-only note in short clauses. Slightly comma-dense in the middle sentence, but every clause carries information.

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?

For a 22-parameter, no-output-schema search tool, the description covers purpose, scope selection, filter categories, pagination and the two headline return metrics, leaving the detailed field semantics to an 82%-covered schema. It omits auth/rate-limit context for an external source, which is the only meaningful gap.

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?

Schema description coverage is 82%, so the schema already documents area_id vs location precedence, date formats, units (SEK, m²) and sort/view defaults. The description only groups filter categories at a high level (price, date, rooms, area, object type) and adds no semantics beyond the schema — the baseline 3 applies.

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?

States a specific verb and resource — searching sold properties (slutpriser) — and names the distinguishing output (achieved final price and over/under-asking %), which cleanly separates it from the active-listing sibling. The phrase 'the comparables for valuation' also tells the agent what this data is for.

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

Usage Guidelines3/5

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

The description implies the use case (valuation comparables) and lists scoping/filter options, but never names or excludes alternatives such as booli_search_listings (active listings) or booli_market_stats. An agent must infer from the word 'sold' that this is the right tool rather than being routed explicitly.

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.

  1. 2 tool updatesv2.1.3
    • Changedbooli_market_stats2 fields changed
      • changedInput schema / properties / sort / description
        Previous value: -"Sort key (default: newest published)."New value: +"Sort key (default: soldDate — most recent sales first with ascending false)."
      • changedInput schema / properties / sort / enum
        Previous value: -[
        -  "published",
        -  "listPrice",
        -  "listSqmPrice",
        -  "rooms",
        -  "livingArea",
        -  "rent",
        -  "plotArea"
        -]New value: +[
        +  "published",
        +  "listPrice",
        +  "listSqmPrice",
        +  "rooms",
        +  "livingArea",
        +  "rent",
        +  "plotArea",
        +  "soldDate",
        +  "soldPrice"
        +]
    • Changedbooli_search_sold2 fields changed
      • changedInput schema / properties / sort / description
        Previous value: -"Sort key (default: newest published)."New value: +"Sort key (default: soldDate — most recent sales first with ascending false)."
      • changedInput schema / properties / sort / enum
        Previous value: -[
        -  "published",
        -  "listPrice",
        -  "listSqmPrice",
        -  "rooms",
        -  "livingArea",
        -  "rent",
        -  "plotArea"
        -]New value: +[
        +  "published",
        +  "listPrice",
        +  "listSqmPrice",
        +  "rooms",
        +  "livingArea",
        +  "rent",
        +  "plotArea",
        +  "soldDate",
        +  "soldPrice"
        +]
  2. 6 tool updatesv2.0.0
    • Changedbooli_get_listing1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedbooli_healthcheck1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedbooli_market_stats1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedbooli_search_areas1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedbooli_search_listings1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
    • Changedbooli_search_sold1 field changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
  3. 4 tool updatesv1.3.1
    • Changedbooli_get_listing2 fields changed
      • removedInput schema / properties / compact
        Removed value: -{
        -  "description": "Return a slim summary instead of the full raw record (default false).",
        -  "type": "boolean"
        -}
      • addedInput schema / properties / view
        Added 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"
        +}
    • Changedbooli_market_stats2 fields changed
      • removedInput schema / properties / compact
        Removed value: -{
        -  "description": "Return slim summary records (default true). Set false for full raw fields.",
        -  "type": "boolean"
        -}
      • addedInput schema / properties / view
        Added 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"
        +}
    • Changedbooli_search_listings2 fields changed
      • removedInput schema / properties / compact
        Removed value: -{
        -  "description": "Return slim summary records (default true). Set false for full raw fields.",
        -  "type": "boolean"
        -}
      • addedInput schema / properties / view
        Added 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"
        +}
    • Changedbooli_search_sold2 fields changed
      • removedInput schema / properties / compact
        Removed value: -{
        -  "description": "Return slim summary records (default true). Set false for full raw fields.",
        -  "type": "boolean"
        -}
      • addedInput schema / properties / view
        Added 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"
        +}
  4. 6 tool updatesv1.0.0
    • Changedbooli_get_listing3 fields changed
      • removedInput schema / properties / booli_id
        Removed value: -{
        -  "description": "The listing's Booli id (e.g. \"1579812\").",
        -  "type": "string"
        -}
      • addedInput schema / properties / residence_id
        Added value: +{
        +  "description": "The property's residence id (e.g. \"4370936\" from /bostad/4370936).",
        +  "type": "string"
        +}
      • changedInput schema / required
        Previous value: -[
        -  "booli_id"
        -]New value: +[
        +  "residence_id"
        +]
    • Removedbooli_get_sold
    • Changedbooli_market_stats13 fields changed
      • changedInput schema / properties / area_id / description
        Previous 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`."
      • addedInput schema / properties / ascending
        Added value: +{
        +  "description": "Sort ascending (default false).",
        +  "type": "boolean"
        +}
      • removedInput schema / properties / bbox
        Removed value: -{
        -  "description": "Bounding box \"lat_lo,lng_lo,lat_hi,lng_hi\" (SW then NE corner).",
        -  "type": "string"
        -}
      • removedInput schema / properties / center
        Removed value: -{
        -  "description": "Coordinate \"lat,lng\" (e.g. \"59.34674,18.0603\"); use with `dim`.",
        -  "type": "string"
        -}
      • removedInput schema / properties / dim
        Removed value: -{
        -  "description": "Rectangle size in metres \"w,h\" (e.g. \"400,500\"), used with `center`.",
        -  "type": "string"
        -}
      • removedInput schema / properties / limit
        Removed value: -{
        -  "description": "Default 30, max 100.",
        -  "maximum": 100,
        -  "minimum": 1,
        -  "type": "integer"
        -}
      • addedInput schema / properties / location
        Added 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"
        +}
      • removedInput schema / properties / max_rent
        Removed value: -{
        -  "description": "SEK/month",
        -  "minimum": 0,
        -  "type": "number"
        -}
      • changedInput schema / properties / object_type / description
        Previous 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."
      • removedInput schema / properties / offset
        Removed value: -{
        -  "description": "Pagination offset.",
        -  "maximum": 9007199254740991,
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • addedInput schema / properties / page
        Added value: +{
        +  "description": "1-based page (default 1).",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • removedInput schema / properties / q
        Removed value: -{
        -  "description": "Free-text area search (e.g. \"Nacka\", \"Södermalm\"). One of q / area_id / center / bbox scopes the search.",
        -  "type": "string"
        -}
      • addedInput schema / properties / sort
        Added value: +{
        +  "description": "Sort key (default: newest published).",
        +  "enum": [
        +    "published",
        +    "listPrice",
        +    "listSqmPrice",
        +    "rooms",
        +    "livingArea",
        +    "rent",
        +    "plotArea"
        +  ],
        +  "type": "string"
        +}
    • Changedbooli_search_areas8 fields changed
      • removedInput schema / properties / lat
        Removed value: -{
        -  "description": "Latitude; use together with `lng`.",
        -  "type": "number"
        -}
      • changedInput schema / properties / limit / description
        Previous value: -"Default 10, max 50."New value: +"Max results (default 10)."
      • removedInput schema / properties / lng
        Removed value: -{
        -  "description": "Longitude; use together with `lat`.",
        -  "type": "number"
        -}
      • removedInput schema / properties / only_with_listings
        Removed value: -{
        -  "description": "Only return areas that currently have listings for sale.",
        -  "type": "boolean"
        -}
      • removedInput schema / properties / only_with_sold
        Removed value: -{
        -  "description": "Only return areas that have sold listings.",
        -  "type": "boolean"
        -}
      • removedInput schema / properties / q
        Removed value: -{
        -  "description": "Place-name search string (e.g. \"Nacka\").",
        -  "type": "string"
        -}
      • addedInput schema / properties / query
        Added value: +{
        +  "description": "Place-name search string (e.g. \"Nacka\", \"Södermalm\").",
        +  "type": "string"
        +}
      • addedInput schema / required
        Added value: +[
        +  "query"
        +]
    • Changedbooli_search_listings13 fields changed
      • changedInput schema / properties / area_id / description
        Previous 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`."
      • addedInput schema / properties / ascending
        Added value: +{
        +  "description": "Sort ascending (default false).",
        +  "type": "boolean"
        +}
      • removedInput schema / properties / bbox
        Removed value: -{
        -  "description": "Bounding box \"lat_lo,lng_lo,lat_hi,lng_hi\" (SW then NE corner).",
        -  "type": "string"
        -}
      • removedInput schema / properties / center
        Removed value: -{
        -  "description": "Coordinate \"lat,lng\" (e.g. \"59.34674,18.0603\"); use with `dim`.",
        -  "type": "string"
        -}
      • removedInput schema / properties / dim
        Removed value: -{
        -  "description": "Rectangle size in metres \"w,h\" (e.g. \"400,500\"), used with `center`.",
        -  "type": "string"
        -}
      • removedInput schema / properties / limit
        Removed value: -{
        -  "description": "Default 30, max 100.",
        -  "maximum": 100,
        -  "minimum": 1,
        -  "type": "integer"
        -}
      • addedInput schema / properties / location
        Added 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"
        +}
      • removedInput schema / properties / max_rent
        Removed value: -{
        -  "description": "SEK/month",
        -  "minimum": 0,
        -  "type": "number"
        -}
      • changedInput schema / properties / object_type / description
        Previous 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."
      • removedInput schema / properties / offset
        Removed value: -{
        -  "description": "Pagination offset.",
        -  "maximum": 9007199254740991,
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • addedInput schema / properties / page
        Added value: +{
        +  "description": "1-based page (default 1).",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • removedInput schema / properties / q
        Removed value: -{
        -  "description": "Free-text area search (e.g. \"Nacka\", \"Södermalm\"). One of q / area_id / center / bbox scopes the search.",
        -  "type": "string"
        -}
      • addedInput schema / properties / sort
        Added value: +{
        +  "description": "Sort key (default: newest published).",
        +  "enum": [
        +    "published",
        +    "listPrice",
        +    "listSqmPrice",
        +    "rooms",
        +    "livingArea",
        +    "rent",
        +    "plotArea"
        +  ],
        +  "type": "string"
        +}
    • Changedbooli_search_sold13 fields changed
      • changedInput schema / properties / area_id / description
        Previous 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`."
      • addedInput schema / properties / ascending
        Added value: +{
        +  "description": "Sort ascending (default false).",
        +  "type": "boolean"
        +}
      • removedInput schema / properties / bbox
        Removed value: -{
        -  "description": "Bounding box \"lat_lo,lng_lo,lat_hi,lng_hi\" (SW then NE corner).",
        -  "type": "string"
        -}
      • removedInput schema / properties / center
        Removed value: -{
        -  "description": "Coordinate \"lat,lng\" (e.g. \"59.34674,18.0603\"); use with `dim`.",
        -  "type": "string"
        -}
      • removedInput schema / properties / dim
        Removed value: -{
        -  "description": "Rectangle size in metres \"w,h\" (e.g. \"400,500\"), used with `center`.",
        -  "type": "string"
        -}
      • removedInput schema / properties / limit
        Removed value: -{
        -  "description": "Default 30, max 100.",
        -  "maximum": 100,
        -  "minimum": 1,
        -  "type": "integer"
        -}
      • addedInput schema / properties / location
        Added 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"
        +}
      • removedInput schema / properties / max_rent
        Removed value: -{
        -  "description": "SEK/month",
        -  "minimum": 0,
        -  "type": "number"
        -}
      • changedInput schema / properties / object_type / description
        Previous 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."
      • removedInput schema / properties / offset
        Removed value: -{
        -  "description": "Pagination offset.",
        -  "maximum": 9007199254740991,
        -  "minimum": 0,
        -  "type": "integer"
        -}
      • addedInput schema / properties / page
        Added value: +{
        +  "description": "1-based page (default 1).",
        +  "maximum": 9007199254740991,
        +  "minimum": 1,
        +  "type": "integer"
        +}
      • removedInput schema / properties / q
        Removed value: -{
        -  "description": "Free-text area search (e.g. \"Nacka\", \"Södermalm\"). One of q / area_id / center / bbox scopes the search.",
        -  "type": "string"
        -}
      • addedInput schema / properties / sort
        Added value: +{
        +  "description": "Sort key (default: newest published).",
        +  "enum": [
        +    "published",
        +    "listPrice",
        +    "listSqmPrice",
        +    "rooms",
        +    "livingArea",
        +    "rent",
        +    "plotArea"
        +  ],
        +  "type": "string"
        +}
  5. 7 tool updatesv0.0.0
    • First observedbooli_get_listing
    • First observedbooli_get_sold
    • First observedbooli_healthcheck
    • First observedbooli_market_stats
    • First observedbooli_search_areas
    • First observedbooli_search_listings
    • First observedbooli_search_sold

TDQS

A4.1/5.0

Scored across 6 tools

Disambiguation5/5

Each tool targets a distinct purpose: area resolution, active listing search, single-listing detail, sold-comparable search, aggregate stats, and a bridge healthcheck. The descriptions clearly draw boundaries (e.g. market_stats vs search_sold), so an agent can select reliably.

Naming Consistency4/5

All tools share a consistent booli_ prefix and snake_case, with search_*/get_* following a predictable verb_noun pattern. market_stats and healthcheck deviate from verb_noun but remain clear and readable.

Tool Count5/5

Six tools is well-scoped for a read-only real-estate data server, and each tool earns its place (search, detail, areas, stats, diagnostics). No redundancy or padding.

Completeness4/5

The surface covers the full read path: area resolution feeds both listing and sold searches, plus single-item detail and aggregated valuation stats. As a read-only server, mutation gaps are expected, though a performance/valuation-history helper would round it out.

Maintenance

ActivityActive
ResponsivenessResponsive

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    Not graded
    maintenance
    Enables 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.
    3
    1
    -
  • A
    license
    C
    quality
    D
    maintenance
    Enables 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.
    14
    3
    MIT
  • A
    license
    Not graded
    quality
    F
    maintenance
    Provides real-time access to Zillow real estate data, enabling property search, details, Zestimates, market trends, and mortgage calculations via natural language.
    7 npm
    56
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables searching Korean apartment listings, market prices, and recent transactions via Naver Real Estate through natural language.
    6
    MIT