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

9.2 KiB

PROJECT.md — module map

The repo at a glance. For the why and the rules, read PRD.md §12 and §17. For the workflow, read AGENTS.md.


Source tree

finn-mcp/
├── pyproject.toml
├── Makefile
├── README.md                   ← user-facing overview
├── USAGE.md                    ← full user guide
├── PRD.md                      ← product spec + architecture (§17 = constitution)
├── PROJECT.md                  ← this file
├── AGENTS.md                   ← workflow for AI agents and contributors
├── CLEANUP.md                  ← pre-Phase-2 cleanup runbook
├── IMPLEMENTATION.md           ← Phase 2 build runbook (12 steps)
│
├── .github/
│   ├── copilot-instructions.md
│   └── instructions/
│       ├── python.instructions.md
│       ├── mcp.instructions.md
│       ├── cli.instructions.md
│       ├── tests.instructions.md
│       ├── clean-code.instructions.md
│       └── docs.instructions.md            ← context7 lookup rules
│
├── finn_eiendom/                           ← the package
│   ├── __init__.py
│   ├── __main__.py                         ← python -m finn_eiendom → CLI
│   ├── config.py                           ← env vars, defaults, TTLs
│   ├── models.py                           ← Pydantic v2 models
│   ├── parser.py                           ← Norwegian number/area/URL/finnkode normalization
│   ├── http.py                             ← async httpx client w/ retry + delay
│   ├── cache.py                            ← SQLite schema + persistence
│   ├── search.py                           ← FINN search HTML parsing
│   ├── ad.py                               ← FINN listing HTML parsing
│   ├── eiendom_no.py                       ← Eiendom.no unit search/detail, unit_vector, comps
│   ├── scoring.py                          ← score model + classifications
│   ├── feedback.py                         ← verdicts + soft preference signal
│   ├── analysis.py                         ← shortlist + summary assembly
│   ├── service.py                          ← get_or_fetch_* + thin facade for MCP and CLI
│   ├── formatting.py                       ← render_* helpers (json/markdown/table) — shared by MCP and CLI
│   ├── mcp_server.py                       ← FastMCP wrappers around service.py
│   └── cli.py                              ← typer wrappers around service.py
│
├── tests/
│   ├── conftest.py
│   ├── fixtures.py
│   ├── fixtures/                           ← HTML + JSON samples
│   ├── test_parser.py
│   ├── test_search.py
│   ├── test_ad.py
│   ├── test_eiendom_no.py
│   ├── test_scoring.py
│   ├── test_cache.py
│   ├── test_http.py                        ← retry + delay behavior
│   ├── test_service.py                     ← get_or_fetch_* + analyze_*
│   ├── test_formatting.py                  ← render_* roundtrips
│   ├── test_models.py                      ← Pydantic v2 roundtrips
│   ├── test_mcp_server.py                  ← tool registration + error envelope
│   ├── test_cli.py                         ← Typer CliRunner
│   └── test_architecture.py                ← import-graph invariants (PRD A10)
│
└── data/                                   ← gitignored; SQLite cache lives here
    └── finn.sqlite

Module responsibilities

Single-home rule: every concern lives in exactly one module. See PRD.md §17.2 for the full table.

Module Owns Imports allowed
config.py env-var loading, defaults, TTL constants stdlib
models.py Pydantic v2 models stdlib, pydantic
parser.py Norwegian text normalization (numbers, dates, URLs, finnkode) stdlib
http.py async httpx.AsyncClient, retry on 5xx, delay, user-agent stdlib, httpx
cache.py SQLite schema, reads, writes, TTL stdlib, sqlite3, models
search.py FINN search HTML → cards (BeautifulSoup) stdlib, bs4, parser, http, cache, models
ad.py FINN listing HTML → FinnAd (BeautifulSoup) stdlib, bs4, parser, http, cache, models
eiendom_no.py Eiendom.no unit search/detail, unit_vector, similar-units (msgpack) stdlib, msgpack, http, cache, models
scoring.py 9 score components, total clamping, category classifier stdlib, models
feedback.py feedback storage and retrieval stdlib, cache, models
analysis.py shortlist + summary assembly stdlib, search, ad, eiendom_no, scoring, feedback
service.py cache-aware orchestration; the only place that combines fetch + cache stdlib, config, cache, analysis, ad, eiendom_no, feedback, scoring, models
formatting.py render_* helpers (json/markdown/table) stdlib, models
mcp_server.py FastMCP tool definitions, error wrapping, stdio/HTTP entry stdlib, mcp, pydantic, service, formatting, config, models
cli.py typer command definitions, --format dispatch stdlib, typer, service, formatting, config, models

mcp_server.py and cli.py are siblings — they never import each other. service.py never imports mcp_server or cli. tests/test_architecture.py enforces all of this.


Entry points

Defined in pyproject.toml:

[project.scripts]
finn-eiendom-mcp = "finn_eiendom.mcp_server:main"
finn-eiendom     = "finn_eiendom.cli:app"

So you have:

  • finn-eiendom-mcp — MCP server over stdio (what Claude Desktop calls).
  • finn-eiendom — CLI with all subcommands.
  • python -m finn_eiendom — same as finn-eiendom (via __main__.py).
  • import finn_eiendom — the library, for tests and notebooks.

Dependency graph

                cli.py            mcp_server.py
                   ↓                    ↓
                   └──> formatting.py <──┘
                              │
                              ↓
                         service.py
                              ↓
                        analysis.py
                              ↓
                  ┌───────────┼──────────────┐
                  ↓           ↓              ↓
              search.py    ad.py    eiendom_no.py    scoring.py    feedback.py
                  │           │              │            │            │
                  ↓           ↓              ↓            ↓            ↓
              parser.py   parser.py        cache.py    models.py    cache.py
                  │           │              │
                  ↓           ↓              ↓
                http.py    http.py         http.py

Bottom layer: parser.py, http.py, cache.py, models.py, config.py. They depend only on stdlib + one third-party library each.

The graph is acyclic and points downward. Every arrow can be drawn; no arrow can be drawn upward.


Where to add things

You want to… Add it to…
Parse a new FINN field ad.py or search.py + models.py
Add a new score component scoring.py
Add a new env var config.py
Add a new MCP tool mcp_server.py (after service.py)
Add a new CLI command cli.py (after service.py)
Change how something renders formatting.py
Add a new orchestration / workflow service.py (then add MCP + CLI)
Speak to a new external API new module next to eiendom_no.py
Add a new SQLite table cache.py

For anything else — read PRD.md §17.2 and §17.7.