Motivation
Today Claude Code interacts with BoligWatch by shelling out to python boligwatch.py --peek and parsing the JSON output. This works, but it's a loosely coupled integration — Claude has no structured understanding of what tools are available, what parameters they accept, or what the response schema looks like. It just runs a command and hopes the output is parseable.
Turning BoligWatch into a Model Context Protocol (MCP) server would make it a first-class tool that any MCP client (Claude Code, Claude Desktop, Cursor, VS Code, etc.) can discover and call natively with typed inputs and outputs.
Why MCP over CLI
| Concern |
CLI (--peek / --json) |
MCP server |
| Tool discovery |
Claude must be told what flags exist |
Client auto-discovers available tools and their schemas |
| Parameter validation |
Errors surface as stderr text |
Invalid params rejected before execution with structured errors |
| Structured output |
JSON blob Claude must parse |
Typed response objects the client understands natively |
| Multi-step workflows |
Separate subprocess per action |
Persistent server, multiple tool calls in one session |
| Portability |
Only works via shell access |
Works in Claude Desktop, IDEs, and any MCP client |
Proposed tools
search_listings
Search for rental listings matching criteria. Returns structured listing objects.
Parameters:
city (string[], optional) — cities to search
bbox (object, optional) — { min_lat, min_lng, max_lat, max_lng }
rooms_min / rooms_max (int, optional)
max_rent (int, optional) — max monthly rent in DKK
min_size_m2 (int, optional)
min_rental_period (int, optional)
pet_friendly / balcony / furnished (bool, optional)
only_new (bool, default true) — filter to unseen listings only
get_listing
Fetch full details for a single listing by ID.
mark_seen
Mark one or more listing IDs as seen so they don't appear in future search_listings calls with only_new: true.
get_stats
Return current tracker state — how many listings seen, last check timestamp, etc.
Implementation notes
- Use the MCP Python SDK (
mcp) for the server
- stdio transport is the simplest starting point and works with all clients
- The existing
SearchConfig, Listing, SeenTracker, and fetch_listings() can be reused directly — they're already cleanly separated from the CLI layer
- Keep the CLI entrypoint working alongside the MCP server (they share the same core logic)
- Zero external dependencies is a nice property of the current tool — adding
mcp as a dependency is the tradeoff, but it's the only one needed
Example client config
{
"mcpServers": {
"boligwatch": {
"command": "python",
"args": ["path/to/boligwatch_mcp.py"],
"env": {}
}
}
}
What this unlocks
- Claude can search, filter, and act on listings as native tool calls without prompt engineering around CLI flags
- Works in Claude Desktop and IDE extensions, not just Claude Code terminal sessions
- Composable with other MCP servers (e.g. Playwright MCP for browser automation, Slack MCP for notifications)
- Other MCP clients beyond Claude get access for free
Motivation
Today Claude Code interacts with BoligWatch by shelling out to
python boligwatch.py --peekand parsing the JSON output. This works, but it's a loosely coupled integration — Claude has no structured understanding of what tools are available, what parameters they accept, or what the response schema looks like. It just runs a command and hopes the output is parseable.Turning BoligWatch into a Model Context Protocol (MCP) server would make it a first-class tool that any MCP client (Claude Code, Claude Desktop, Cursor, VS Code, etc.) can discover and call natively with typed inputs and outputs.
Why MCP over CLI
--peek/--json)Proposed tools
search_listingsSearch for rental listings matching criteria. Returns structured listing objects.
Parameters:
city(string[], optional) — cities to searchbbox(object, optional) —{ min_lat, min_lng, max_lat, max_lng }rooms_min/rooms_max(int, optional)max_rent(int, optional) — max monthly rent in DKKmin_size_m2(int, optional)min_rental_period(int, optional)pet_friendly/balcony/furnished(bool, optional)only_new(bool, default true) — filter to unseen listings onlyget_listingFetch full details for a single listing by ID.
mark_seenMark one or more listing IDs as seen so they don't appear in future
search_listingscalls withonly_new: true.get_statsReturn current tracker state — how many listings seen, last check timestamp, etc.
Implementation notes
mcp) for the serverSearchConfig,Listing,SeenTracker, andfetch_listings()can be reused directly — they're already cleanly separated from the CLI layermcpas a dependency is the tradeoff, but it's the only one neededExample client config
{ "mcpServers": { "boligwatch": { "command": "python", "args": ["path/to/boligwatch_mcp.py"], "env": {} } } }What this unlocks