Booli fpx
Query booli.se (Swedish property portal) from a shell with the fpx CLI (@fetchproxy/cli) instead of running the booli-mcp server — resolve areas, search for-sale and sold listings (slutpriser), and read property detail via one-shot GraphQL calls through a signed-in browser tab. Use when you want Booli data without the MCP, in a script, or on a machine where the MCP isn't installed.From its SKILL.md
npx -y skills add chrischall/booli-mcp --skill booli-fpxAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
3.7 KB, as published. Nobody here has run it
Booli via fpx (no MCP)
Booli fronts www.booli.se — including /graphql — with a Cloudflare managed
challenge that 403s any plain curl/Node request. fpx routes the request
through the user's own signed-in browser tab (the Transporter extension),
which has already cleared the challenge, so the same anonymous GraphQL query
succeeds. No Booli login is needed — just a normal open tab.
This is the same data the booli_* MCP tools return (money in SEK, areas
in m², rooms as a number), reached with one CLI call instead of a running
server.
One-time setup
npm install -g @fetchproxy/cli # provides `fpx`
fpx profile add booli --domain booli.se # only the fetch capability is needed
fpx pair -p booli # prints a pair code → approve in Transporter
Requirements: the Transporter browser extension installed, with an open
www.booli.se tab, and its Chrome Site access allowing booli.se.
Pairing persists — after the first approval every later fpx call reuses it.
Core call
Every query is a POST of {"query": "...", "variables": {...}} to the GraphQL
endpoint. Write the body to a file (a heredoc avoids shell-quoting the GraphQL
string), then send it so stdout is the GraphQL JSON, ready for jq:
cat > /tmp/bq.json <<'JSON'
{ "query": "…", "variables": { … } }
JSON
fpx post-json 'https://www.booli.se/graphql' @/tmp/bq.json -p booli | jq '.data'
Ready-to-run query bodies (area lookup, for-sale search, sold search, property
detail) with jq recipes are in references/graphql-queries.md. Exhaustive
field lists live in the repo at src/graphql.ts — the operations here are
compact, live-verified subsets.
The one rule: resolve the area first
Booli searches take a numeric area id (areaId), never a place name.
Always resolve the name first, take the id, then search:
printf '{"query":"query($s:String!){areaSuggestionSearch(search:$s){suggestions{id displayName}}}","variables":{"s":"Nacka"}}' > /tmp/a.json
fpx post-json 'https://www.booli.se/graphql' @/tmp/a.json -p booli \
| jq -r '.data.areaSuggestionSearch.suggestions[] | "\(.id)\t\(.displayName)"'
# 76 Nacka kommun
Pass that id as the search input's areaId (a string). The SearchRequest
input needs areaId, page (1-based), ascending, excludeAncestors: true,
facets: [], filters: [{key,value}], and sort ("" = newest). Filters
reuse the same keys the MCP does (minRooms, maxListPrice, objectType, …).
Exit codes (fetch verbs)
0— success (a GraphQLerrorsarray can still ride in a0body; checkjq '.errors // empty').2— bridge unavailable: extension not connected or pairing pending → runfpx pair -p booli, confirm a booli tab is open.3— bot wall: the tab hasn't cleared Cloudflare → open/refresh awww.booli.setab and retry.4— upstream non-2xx from Booli.
Notes
- Anonymous reads only — the same public GraphQL surface as the MCP; no account data. Stay within booli.se's terms.
fpx health -p boolishows bridge connection state when a call fails.- Property detail is keyed by residence id — the number in a
/bostad/<id>URL, which is a search result'surlfield, notbooliId. - This project is developed and maintained by AI (Claude).