Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
Ole
2026-05-18 21:31:52 +00:00
parent 6eedfffa4d
commit c9383788de
22 changed files with 1614 additions and 42 deletions
+36 -5
View File
@@ -3,10 +3,10 @@
import json
import logging
from typing import Any
import os
from mcp.server.transport_security import TransportSecuritySettings
from mcp.server.fastmcp import FastMCP
from .analysis import analyze_search
from .eiendom_no import (
build_unit_vector,
decode_unit_vector,
@@ -20,22 +20,37 @@ from .formatting import (
render_diff,
render_shortlist,
render_similar_units,
render_unit_images,
)
from .service import (
analyze_ad,
analyze_ad_against_comps,
analyze_search,
compare_ads,
find_similar_to_liked,
get_new_ads_since_last_run,
get_or_fetch_ad,
get_or_fetch_eiendom_unit,
get_shortlist,
get_unit_images,
save_feedback,
)
logger = logging.getLogger(__name__)
mcp = FastMCP("finn_eiendom_mcp")
def _build_transport_security() -> TransportSecuritySettings:
allowed = os.getenv("MCP_ALLOWED_HOSTS", "")
if allowed:
hosts = [h.strip() for h in allowed.split(",")]
return TransportSecuritySettings(
enable_dns_rebinding_protection=True,
allowed_hosts=["127.0.0.1:*", "localhost:*", "[::1]:*"] + hosts,
)
return TransportSecuritySettings(enable_dns_rebinding_protection=False)
mcp = FastMCP("finn_eiendom_mcp", transport_security=_build_transport_security())
@mcp.tool(
@@ -56,7 +71,7 @@ async def finn_analyze_search(
result = await analyze_search(
search_url,
max_pages=max_pages,
fetch_details=include_details,
include_details=include_details,
detail_limit=detail_limit,
include_eiendom_no=include_eiendom_no,
)
@@ -125,6 +140,22 @@ async def finn_get_eiendom_unit(unit_code: str, force_refresh: bool = False) ->
return json.dumps({"error": True, "message": str(e)})
@mcp.tool(
description=(
"Fetch and analyze unit images for visual assessment of a property. "
"Returns property photos with metadata for evaluating views, condition, and layout."
)
)
async def finn_analyze_unit_images(unit_code: str, force_refresh: bool = False) -> str:
"""Fetch and return unit images for visual analysis."""
try:
result = await get_unit_images(unit_code, force_refresh=force_refresh)
return render_unit_images(result, "markdown")
except Exception as e:
logger.error(f"Error fetching unit images for {unit_code}: {e}")
return json.dumps({"error": True, "message": str(e)})
@mcp.tool(
description="Fetch comparable recently-sold or for-sale units from Eiendom.no using a "
"base64-encoded unit vector. Returns list of similar units with sale prices."
@@ -296,7 +327,7 @@ async def finn_get_new_ads_since_last_run(search_url: str) -> str:
def main() -> None:
"""Run the FastMCP stdio server."""
"""Run the FastMCP server over stdio (standard MCP transport)."""
mcp.run(transport="stdio")