18 KiB
USAGE.md — finn-eiendom user guide
How to use the tool day-to-day. Covers installation, every CLI command, every MCP tool, Claude Desktop integration, common workflows, environment variables, and troubleshooting.
For the why and the architecture, see README.md and PRD.md.
1. Installation
Requirements
- Python 3.12 or newer (check with
python3 --version) uv(recommended) orpip- macOS, Linux, or WSL2 on Windows
Install
git clone <your-repo-url> finn-mcp
cd finn-mcp
# Option A: uv (preferred — fast)
uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"
# Option B: pip
python3.12 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
Verify:
finn-eiendom --help
finn-eiendom-mcp --help # may exit immediately on stdio mode; that's fine
finn-eiendom doctor # smoke-checks cache, FINN, Eiendom.no reachability
Updating
git pull
source .venv/bin/activate
uv pip install -e ".[dev]"
If pyproject.toml added dependencies, the second command picks them up.
Global install (optional)
If you want finn-eiendom available system-wide without activating the venv:
uv tool install .
# or
pipx install .
2. First-time setup
Set up the data directory
mkdir -p data
SQLite cache lives there at data/finn.sqlite by default. Override with FINN_CACHE_PATH if you want it elsewhere.
Optional: environment file
Create .env in the project root for your usual settings:
FINN_CACHE_PATH=data/finn.sqlite
FINN_MAX_SEARCH_PAGES=3
FINN_DETAIL_LIMIT=20
EIENDOM_NO_ENABLED=true
EIENDOM_NO_SIMILAR_UNITS_ENABLED=true
LOG_LEVEL=INFO
See §7 for the full list of variables.
Verify
finn-eiendom doctor
This pings the cache, reaches FINN once, reaches Eiendom.no once, and reports any failures.
3. CLI reference
Every command runs inside the activated venv.
3.1 Analyze a FINN search
finn-eiendom analyze-search '<finn-search-url>' [options]
| Option | Default | Purpose |
|---|---|---|
--max-pages N |
3 |
Pages of search results to fetch. |
--detail-limit N |
20 |
How many listings to detail-fetch from the result set. |
--no-details |
off | Skip detail fetches; use only search-card data. |
--no-eiendom |
off | Skip Eiendom.no enrichment. |
--with-similar |
off | Fetch similar-units / comps for shortlisted listings. |
--format FMT |
json |
json, markdown, or table. |
Examples:
# Triage in the terminal
finn-eiendom analyze-search 'https://www.finn.no/realestate/homes/search.html?location=0.20061&min_bedrooms=2&price_collective_to=12000000' --format table
# Full JSON for piping into jq
finn-eiendom analyze-search '<url>' --format json | jq '.shortlist[].title'
# Detailed run with comps
finn-eiendom analyze-search '<url>' --detail-limit 30 --with-similar --format markdown
3.2 Drill into one listing
finn-eiendom get-ad <finnkode> [options]
| Option | Default | Purpose |
|---|---|---|
--force-refresh |
off | Bypass the 24h cache and refetch. |
--no-eiendom |
off | Skip Eiendom.no enrichment. |
--with-similar |
off | Fetch similar-units / comps. |
--format FMT |
json |
json or markdown. |
finn-eiendom get-ad 462400360 --format markdown
finn-eiendom get-ad 462400360 --force-refresh --with-similar
3.3 Compare listings
finn-eiendom compare <finnkode> <finnkode> [<finnkode>...] [options]
| Option | Default | Purpose |
|---|---|---|
--no-eiendom |
off | Skip Eiendom.no enrichment. |
--no-comps |
off | Skip similar-units / comps. |
--format FMT |
json |
json, markdown, or table. |
finn-eiendom compare 462400360 461153194 --format markdown
finn-eiendom compare 462400360 461153194 462400360 --format table
Up to 10 finnkoder per call.
3.4 Feedback
finn-eiendom save-feedback <finnkode> <verdict> [--notes "..."]
Verdict vocabulary: liked, rejected, interesting, bargain_candidate, risk_object, viewing_candidate, viewed, too_expensive, too_small, too_far_out, too_high_risk, likes_location, likes_layout, dislikes_area.
finn-eiendom save-feedback 462400360 liked --notes "balcony, view, check wet rooms"
finn-eiendom save-feedback 461153194 rejected --notes "too far from city center"
liked verdicts feed the similar-to-liked command.
3.5 New / removed / changed listings
finn-eiendom diff '<finn-search-url>' [--format FMT]
Compares the current search results against the previous run for the same normalized URL and reports new finnkoder, removed finnkoder, and changed listings (price, common costs, status).
finn-eiendom diff '<url>' --format table
Useful as a daily cron:
0 9 * * * cd /path/to/finn-mcp && .venv/bin/finn-eiendom diff 'https://www.finn.no/...' --format markdown >> diff.log
3.6 Shortlist history
finn-eiendom shortlist [--run-id ID] [--limit N] [--format FMT]
Without --run-id, returns the latest saved shortlist.
3.7 Eiendom.no commands
finn-eiendom resolve-unit '<finn-listing-url>' # find unitCode for a FINN listing
finn-eiendom get-unit <unit_code> [--force-refresh] # fetch unit detail
finn-eiendom enrich-ad <finnkode> [--with-similar] # FINN + Eiendom.no combined
finn-eiendom build-vector <unit_code> # build the base64url unit_vector
finn-eiendom decode-vector <unit_vector> # decode for inspection
finn-eiendom similar-units <unit_vector> [--status RECENTLY_SOLD|FOR_SALE|CURRENT]
3.8 Find similar to liked
finn-eiendom similar-to-liked <finnkode> [--mode recommendations|comps] [--status STATUS]
The listing must have a liked feedback row. Defaults to mode=recommendations, status=FOR_SALE — i.e. find active listings similar to this one. Use --mode comps --status RECENTLY_SOLD to get comparable sales instead.
3.9 Price analysis against comps
finn-eiendom analyze-against-comps <finnkode>
Returns price_position (below_estimate / within_range / above_estimate), sqm_price_position (cheap / normal / expensive), comparable_score, and a confidence label.
3.10 Cache management
finn-eiendom cache stats # row counts and TTL summary
finn-eiendom cache clear # purge everything except feedback
finn-eiendom cache clear-html # only purge raw HTML
finn-eiendom cache clear-json # only purge raw JSON
Feedback is never purged by cache clear — feedback is permanent until explicitly deleted via SQL.
3.11 MCP server
finn-eiendom serve # stdio (default)
finn-eiendom serve --transport http --port 8010 # HTTP for n8n / multi-client
In HTTP mode the server listens on http://127.0.0.1:8010/mcp with operational endpoints GET /health, GET /version, GET /debug/config.
There's also a shorthand finn-eiendom-mcp that starts stdio mode directly — that's what Claude Desktop calls.
3.12 Misc
finn-eiendom config show # print resolved configuration
finn-eiendom config path # print SQLite cache path
finn-eiendom doctor # smoke checks
finn-eiendom version
4. MCP tools (for Claude Desktop / n8n / agents)
All tools use the finn_ prefix. They mirror the CLI commands 1:1 — same defaults, same semantics.
| Tool | Purpose |
|---|---|
finn_analyze_search |
Analyze a FINN search URL and return a ranked shortlist. |
finn_get_ad |
Fetch structured data for one finnkode. |
finn_compare_ads |
Compare multiple listings side by side. |
finn_save_feedback |
Store feedback/verdict/notes. |
finn_get_shortlist |
Fetch a stored shortlist from a previous run. |
finn_get_new_ads_since_last_run |
Detect new / removed / changed listings. |
finn_resolve_eiendom_unit |
Map FINN URL → Eiendom.no unitCode. |
finn_get_eiendom_unit |
Fetch Eiendom.no unit detail by unitCode. |
finn_enrich_ad |
Combine FINN listing + Eiendom.no enrichment. |
finn_build_unit_vector |
Build a unit_vector from a unitCode. |
finn_decode_unit_vector |
Decode a unit_vector for inspection. |
finn_get_similar_units |
Fetch comps / recommendations. |
finn_find_similar_to_liked_ad |
Find properties similar to one you liked. |
finn_analyze_ad_against_comps |
Evaluate a listing against RECENTLY_SOLD comps. |
Every tool accepts a response_format parameter ("json" or "markdown"). Errors come back as {"error": true, "code": "<ExceptionName>", "message": "..."}.
5. Claude Desktop setup
Config file
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Direct entry-point (recommended)
{
"mcpServers": {
"finn-eiendom": {
"command": "/absolute/path/to/finn-mcp/.venv/bin/finn-eiendom-mcp",
"env": {
"FINN_CACHE_PATH": "/absolute/path/to/finn-mcp/data/finn.sqlite",
"EIENDOM_NO_ENABLED": "true",
"EIENDOM_NO_SIMILAR_UNITS_ENABLED": "true",
"LOG_LEVEL": "INFO"
}
}
}
}
The command must be the absolute path to the venv's finn-eiendom-mcp binary. Don't rely on $PATH here — Claude Desktop doesn't inherit your shell environment.
Alternative: via uv
{
"mcpServers": {
"finn-eiendom": {
"command": "uv",
"args": ["run", "finn-eiendom-mcp"],
"cwd": "/absolute/path/to/finn-mcp"
}
}
}
Verify
- Restart Claude Desktop.
- Look for
finn-eiendomin the MCP servers indicator (usually a hammer icon). - Ask in any chat: "Use the finn-eiendom server to analyze this search: ..."
If it doesn't show up, check the Claude Desktop logs:
- macOS:
~/Library/Logs/Claude/mcp-server-finn-eiendom.log - Linux:
~/.local/share/Claude/logs/mcp-server-finn-eiendom.log
stdout output from the server is a fatal error — the server must only log to stderr.
6. Common workflows
6.1 Daily triage
# Morning routine
finn-eiendom diff 'https://www.finn.no/...' --format table
# Detail-fetch only what's new or changed
finn-eiendom analyze-search 'https://www.finn.no/...' --detail-limit 10 --format markdown
6.2 Weekly deep dive in Claude Desktop
Read my latest finn-eiendom shortlist and group the top 10 by category (bargain / safe / hybel / lifestyle). For each, summarize the three most important risks and the three most important broker questions.
6.3 Pre-viewing prep
# Mark candidates for viewing
finn-eiendom save-feedback 462400360 viewing_candidate --notes "Saturday 14:00"
# Get the full data + comps
finn-eiendom get-ad 462400360 --with-similar --format markdown > viewing_prep_462400360.md
Then in Claude Desktop:
Read the saved markdown for finnkode 462400360 and prepare a viewing checklist: wet rooms to inspect, common-costs questions, hybel-approval question, neighbor questions.
6.4 Comparing finalists
finn-eiendom compare 462400360 461153194 459333210 --format markdown > finalists.md
6.5 Build a recommendation set from liked properties
# After you've liked a few
finn-eiendom save-feedback 462400360 liked
finn-eiendom save-feedback 461153194 liked
# Get recommendations similar to each
finn-eiendom similar-to-liked 462400360 --mode recommendations --status FOR_SALE
finn-eiendom similar-to-liked 461153194 --mode recommendations --status FOR_SALE
7. Environment variables
| Variable | Default | Purpose |
|---|---|---|
FINN_CACHE_PATH |
data/finn.sqlite |
SQLite DB path |
FINN_MAX_SEARCH_PAGES |
3 |
Max search pages per analyze |
FINN_DETAIL_LIMIT |
20 |
Max detail fetches per analyze |
FINN_REQUEST_DELAY_SECONDS |
2 |
Seconds between FINN requests |
FINN_USER_AGENT |
personal-finn-eiendom-analyzer/0.1 |
HTTP User-Agent |
FINN_CACHE_TTL_SEARCH_MINUTES |
60 |
Search cache TTL |
FINN_CACHE_TTL_AD_HOURS |
24 |
Listing cache TTL |
EIENDOM_NO_ENABLED |
true |
Enable Eiendom.no enrichment |
EIENDOM_NO_BASE_URL |
https://api.eiendom.no/api/v1 |
API base URL |
EIENDOM_NO_CACHE_TTL_HOURS |
24 |
Unit/similar cache TTL |
EIENDOM_NO_REQUEST_DELAY_SECONDS |
1 |
Seconds between Eiendom.no calls |
EIENDOM_NO_SIMILAR_UNITS_ENABLED |
true |
Enable similar-units |
EIENDOM_NO_SIMILAR_UNITS_DEFAULT_STATUS |
RECENTLY_SOLD |
Default comps status |
HJEMLA_ENABLED |
false |
Enable optional Hjemla API |
LOG_LEVEL |
INFO |
Log level |
MCP_TRANSPORT |
stdio |
stdio or streamable_http |
MCP_HTTP_HOST |
127.0.0.1 |
HTTP bind address |
MCP_HTTP_PORT |
8010 |
HTTP port |
Set them in .env, in your shell, or in the Claude Desktop env block per §5.
8. Troubleshooting
Claude Desktop doesn't see the server
- The
commandpath must be absolute and point at the venv's binary. - Check
~/Library/Logs/Claude/mcp-server-finn-eiendom.log(macOS) for a Python traceback. - The server must not write to stdout — any
print()in the code breaks JSON-RPC. If you're hacking on it and see a frame parse error, that's the cause. - Restart Claude Desktop after config changes (
Cmd+Q, not just close the window).
"Module not found" when running CLI
The venv isn't activated, or the package isn't installed in editable mode.
source .venv/bin/activate
uv pip install -e ".[dev]"
Eiendom.no enrichment is unavailable
This is graceful degradation when:
- The FINN URL can't be matched to a
unitCode(rare, but happens for unusual addresses). - Eiendom.no rate-limited or returned 5xx.
- The unit was deleted from Eiendom.no's index.
Check the log for the warning. The listing analysis continues without enrichment.
Similar-units returns nothing
- Verify
EIENDOM_NO_SIMILAR_UNITS_ENABLED=true. - The
unit_vectormight be empty / malformed — checkfinn-eiendom decode-vector <unit_vector>. - Try
--status FOR_SALEifRECENTLY_SOLDis sparse, or vice versa.
Slow first run
The first analyze fills the cache. Subsequent runs are much faster. Tune FINN_REQUEST_DELAY_SECONDS and EIENDOM_NO_REQUEST_DELAY_SECONDS if you're impatient — but don't drop them too low, the whole point of caching is to be polite.
Stale results
Cache TTLs:
- Search: 60 minutes
- FINN listing: 24 hours
- Eiendom.no unit: 24 hours
- Similar-units: 24 hours
Force a refresh with --force-refresh on get-ad or get-unit, or wipe with finn-eiendom cache clear.
pytest fails after pulling new changes
source .venv/bin/activate
uv pip install -e ".[dev]" # re-sync dependencies
pytest -x # find the first failure
If a test fails with a network-related error, that's a bug — tests should never hit the network. Report it.
9. What this tool is not
- Not a public API. Don't expose the HTTP transport on the open internet.
- Not financial, legal, or valuation advice. Scores and estimates are decision support.
- Not a bidding agent. It will never contact a broker or place a bid for you.
- Not a crawler. Use it for the searches you'd be manually browsing anyway — at your own pace.
- Not a substitute for a real condition report (
tilstandsrapport), a real lawyer, or a real broker.
10. Getting help
README.md— overviewPRD.md— full product spec and architectureAGENTS.md— workflow rules for contributors.github/instructions/*.md— per-topic conventions
For bugs, open an issue in the repo with: the exact command run, the full traceback or unexpected output, the version (finn-eiendom version), and a redacted FINN URL if relevant.