Files
finn-mcp/USAGE.md
T
2026-05-16 06:54:17 +00:00

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) or pip
  • 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.

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

  1. Restart Claude Desktop.
  2. Look for finn-eiendom in the MCP servers indicator (usually a hammer icon).
  3. 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

  1. The command path must be absolute and point at the venv's binary.
  2. Check ~/Library/Logs/Claude/mcp-server-finn-eiendom.log (macOS) for a Python traceback.
  3. 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.
  4. 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_vector might be empty / malformed — check finn-eiendom decode-vector <unit_vector>.
  • Try --status FOR_SALE if RECENTLY_SOLD is 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

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.