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

6.4 KiB

AGENTS.md — Workflow for AI agents on finn-eiendom-mcp

This is the master doc for any AI agent (Claude, Copilot, Cursor, etc.) working in this repo. Read this first, then the more specific files it references.


Read order

Before changing code, read:

  1. PRD.md — what we're building and why. Especially §17 ("Code ownership and anti-duplication") — that section is the constitution.
  2. PROJECT.md — module map.
  3. This file — workflow.
  4. The relevant .github/instructions/*.md:
    • python.instructions.md — Python conventions.
    • mcp.instructions.md — MCP tool rules.
    • cli.instructions.md — CLI command rules.
    • tests.instructions.md — testing conventions.
    • clean-code.instructions.md — best practices and DRY enforcement.
    • docs.instructions.md — when and how to use the context7 MCP server for library documentation.

If something in code contradicts the PRD, the PRD wins. If you change behavior, update both the PRD and the relevant instruction file in the same change.


Runtime — local venv (default)

This project runs in a project-local virtualenv. Docker is supported for packaging but is not required for development.

One-time setup

# from the project root
uv venv                           # or: python3.12 -m venv .venv
source .venv/bin/activate
uv pip install -e ".[dev]"        # or: pip install -e ".[dev]"

Python 3.12+ is required.

Daily commands

All commands are run inside the activated .venv:

pytest                            # tests
ruff check .                      # lint
ruff format .                     # format
mypy finn_eiendom                 # type-check
finn-eiendom --help               # CLI entrypoint
finn-eiendom-mcp                  # MCP server (stdio)
finn-eiendom serve --transport http --port 8010   # MCP server (HTTP)

Never

  • Install packages globally (pip install ... outside a venv).
  • Use sudo pip.
  • Mutate the host Python.
  • Add dependencies without updating pyproject.toml.

Adding a dependency

uv pip install <package>          # ad-hoc, then:
# edit pyproject.toml to record it
uv pip install -e ".[dev]"        # reinstall in editable mode

Architecture in one screen

cli.py (typer)   mcp_server.py (FastMCP)        ← thin, parallel front ends
        \             /
         \           /
          service.py            ← orchestration: get_or_fetch, analyze_*
              ↓
          analysis.py           ← shortlist + summary
              ↓
   search / ad / eiendom_no / scoring / feedback
              ↓
        parser / http / cache
              ↓
       FINN HTML + Eiendom.no JSON + SQLite

formatting.py sits next to service.py and is shared by both CLI and MCP for json, markdown, and table rendering.

The single-home rule: every piece of logic has exactly one home. If you're tempted to add it in two places, you're wrong about one — push it down a layer and call it from both. See PRD.md §17.2 for the full ownership table.


The five hard rules

These are non-negotiable. Architecture tests in tests/test_architecture.py enforce them.

  1. mcp_server.py and cli.py are siblings. They never call each other. Both call only service, formatting, models, and config.
  2. service.py is the only place that combines cache + fetch. Nothing above it touches HTTP or SQLite directly.
  3. httpx lives in http.py. Nowhere else.
  4. sqlite3 lives in cache.py. Nowhere else.
  5. Output formatting lives in formatting.py. No inline rendering in CLI or MCP tool bodies.

If you have to break one of these to ship a feature, the feature is wrong — fix the design first.


Adding a feature — the checklist

For any new tool / command / behavior:

  1. Decide the home using the table in PRD.md §17.2.
  2. Write the function in service.py (or extend analysis.py if it's pure orchestration).
  3. Add a test in tests/test_service.py.
  4. Add a thin MCP tool in mcp_server.pyresponse_format aware.
  5. Add a thin CLI command in cli.py--format aware.
  6. Add the renderer in formatting.py if output is non-trivial.
  7. Add tests in tests/test_mcp_server.py and tests/test_cli.py.
  8. Update PRD.md and any affected .github/instructions/*.md.

If steps 4 or 5 need more than ~20 lines, logic has leaked out of the service layer. Push it back down.


Clean code

See .github/instructions/clean-code.instructions.md. Highlights:

  • Type hints everywhere.
  • Functions stay small; one job per function.
  • Names describe intent (get_or_fetch_ad, not process).
  • Comments explain why, never what the code already says.
  • DRY: if you write the same regex / SQL / format string twice, extract it.
  • Errors fail loudly with actionable messages. No silent except: pass.
  • No dead code, no commented-out blocks left in the tree.

Documentation lookups — use context7

When uncertain about a library's API (FastMCP decorators, Pydantic v2 validators, Typer command patterns, httpx async, msgpack, pytest-asyncio, respx, BeautifulSoup selectors, etc.), use the context7 MCP server. Do not guess from training-data memory.

Pattern (full details in .github/instructions/docs.instructions.md):

  1. context7:resolve-library-id with the library name → get the canonical ID.
  2. context7:query-docs with that ID + a focused topic.

Use context7 before writing the code, not after a test fails. If context7 returns nothing useful, search the library's official docs, then write the smallest possible spike to verify.


Safety and compliance

  • Private, low-frequency use only.
  • Respect FINN / Eiendom.no rate limits and bot protection.
  • Cache aggressively; never bulk-harvest.
  • stdio MCP servers log to stderr only — anything on stdout breaks the JSON-RPC frame.
  • Scores and estimates are decision support, never legal / technical / financial advice.

Implementation order (Phase 2)

Follow PRD.md §29 step-by-step. Each step is independently mergeable:

  1. Switch dev workflow to local venv + update instruction files (this change).
  2. Pydantic v2 cleanup.
  3. Service layer + tests.
  4. Formatting layer + tests.
  5. HTTP retry on 5xx + tests.
  6. Replace FastAPI with FastMCP stdio server.
  7. CLI with typer.
  8. Diff workflow.
  9. Compare workflow.
  10. Similar-to-liked.
  11. Architecture tests.
  12. README + Claude Desktop config.