Add logging for MCP tool function calls with parameters

Added log_mcp_call() helper function that logs all MCP tool invocations
with their parameters at INFO level. This provides:

- Better debugging and monitoring capabilities
- Clear visibility into which tools are being called and with what parameters
- Smart parameter formatting (truncates long strings, summarizes long lists)
- Consistent logging format across all 10 MCP tools

Example log output:
INFO - MCP tool called: find_recent_deals_for_address(address=סוקולוב 38 חולון, years_back=2, radius_meters=30, max_deals=100, deal_type=2)

This helps track API usage patterns and debug issues in production.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Nitzan P
2025-11-26 23:24:23 +02:00
parent ab59e13936
commit 623d79947b
+76
View File
@@ -29,6 +29,29 @@ mcp = FastMCP("nadlan-mcp")
client = GovmapClient() client = GovmapClient()
def log_mcp_call(func_name: str, **params):
"""
Log MCP tool function calls with their parameters for debugging and monitoring.
Args:
func_name: Name of the MCP tool function being called
**params: Keyword arguments passed to the function
"""
# Format parameters for logging (truncate long strings)
formatted_params = {}
for key, value in params.items():
if isinstance(value, str) and len(value) > 100:
formatted_params[key] = f"{value[:97]}..."
elif isinstance(value, list) and len(value) > 5:
formatted_params[key] = f"[{len(value)} items]"
else:
formatted_params[key] = value
logger.info(
f"MCP tool called: {func_name}({', '.join(f'{k}={v}' for k, v in formatted_params.items())})"
)
def strip_bloat_fields(deals: List[Deal]) -> List[Dict[str, Any]]: def strip_bloat_fields(deals: List[Deal]) -> List[Dict[str, Any]]:
""" """
Remove bloat fields from Deal models to reduce token usage in MCP responses. Remove bloat fields from Deal models to reduce token usage in MCP responses.
@@ -70,6 +93,7 @@ def autocomplete_address(search_text: str) -> str:
Returns: Returns:
JSON string containing matching addresses with their coordinates JSON string containing matching addresses with their coordinates
""" """
log_mcp_call("autocomplete_address", search_text=search_text)
try: try:
response = client.autocomplete_address(search_text) response = client.autocomplete_address(search_text)
@@ -117,6 +141,9 @@ def get_deals_by_radius(latitude: float, longitude: float, radius_meters: int =
Returns: Returns:
JSON string containing polygon metadata (areas with deals nearby) JSON string containing polygon metadata (areas with deals nearby)
""" """
log_mcp_call(
"get_deals_by_radius", latitude=latitude, longitude=longitude, radius_meters=radius_meters
)
try: try:
# Note: GovmapClient expects (longitude, latitude) tuple # Note: GovmapClient expects (longitude, latitude) tuple
# Returns polygon metadata dicts, not Deal objects # Returns polygon metadata dicts, not Deal objects
@@ -153,6 +180,7 @@ def get_street_deals(polygon_id: str, limit: int = 100, deal_type: int = 2) -> s
Returns: Returns:
JSON string containing recent real estate deals for the street JSON string containing recent real estate deals for the street
""" """
log_mcp_call("get_street_deals", polygon_id=polygon_id, limit=limit, deal_type=deal_type)
try: try:
deals = client.get_street_deals(polygon_id, limit, deal_type=deal_type) deals = client.get_street_deals(polygon_id, limit, deal_type=deal_type)
@@ -218,6 +246,14 @@ def find_recent_deals_for_address(
Returns: Returns:
JSON string containing recent real estate deals for the address JSON string containing recent real estate deals for the address
""" """
log_mcp_call(
"find_recent_deals_for_address",
address=address,
years_back=years_back,
radius_meters=radius_meters,
max_deals=max_deals,
deal_type=deal_type,
)
try: try:
deals = client.find_recent_deals_for_address( deals = client.find_recent_deals_for_address(
address, years_back, radius_meters, max_deals, deal_type address, years_back, radius_meters, max_deals, deal_type
@@ -323,6 +359,7 @@ def get_neighborhood_deals(polygon_id: str, limit: int = 100, deal_type: int = 2
Returns: Returns:
JSON string containing recent real estate deals in the specified neighborhood JSON string containing recent real estate deals in the specified neighborhood
""" """
log_mcp_call("get_neighborhood_deals", polygon_id=polygon_id, limit=limit, deal_type=deal_type)
try: try:
deals = client.get_neighborhood_deals(polygon_id, limit, deal_type=deal_type) deals = client.get_neighborhood_deals(polygon_id, limit, deal_type=deal_type)
@@ -387,6 +424,14 @@ def analyze_market_trends(
Returns: Returns:
JSON string containing comprehensive market trend analysis (summarized data, not raw deals) JSON string containing comprehensive market trend analysis (summarized data, not raw deals)
""" """
log_mcp_call(
"analyze_market_trends",
address=address,
years_back=years_back,
radius_meters=radius_meters,
max_deals=max_deals,
deal_type=deal_type,
)
try: try:
# Get deals for the address with larger radius for trend analysis # Get deals for the address with larger radius for trend analysis
deals = client.find_recent_deals_for_address( deals = client.find_recent_deals_for_address(
@@ -589,6 +634,7 @@ def compare_addresses(addresses: List[str]) -> str:
Returns: Returns:
JSON string containing comparative analysis of multiple addresses JSON string containing comparative analysis of multiple addresses
""" """
log_mcp_call("compare_addresses", addresses=addresses)
try: try:
comparisons = [] comparisons = []
@@ -752,6 +798,22 @@ def get_valuation_comparables(
JSON string containing filtered comparable deals with full details. JSON string containing filtered comparable deals with full details.
Returns many comparables so LLM can assess similarity and relevance. Returns many comparables so LLM can assess similarity and relevance.
""" """
log_mcp_call(
"get_valuation_comparables",
address=address,
years_back=years_back,
property_type=property_type,
min_rooms=min_rooms,
max_rooms=max_rooms,
min_price=min_price,
max_price=max_price,
min_area=min_area,
max_area=max_area,
min_floor=min_floor,
max_floor=max_floor,
radius_meters=radius_meters,
max_comparables=max_comparables,
)
try: try:
# Get all deals for the address with higher limits for valuation # Get all deals for the address with higher limits for valuation
deals = client.find_recent_deals_for_address( deals = client.find_recent_deals_for_address(
@@ -866,6 +928,14 @@ def get_deal_statistics(
Returns: Returns:
JSON string containing statistical metrics (mean, median, percentiles, etc.) JSON string containing statistical metrics (mean, median, percentiles, etc.)
""" """
log_mcp_call(
"get_deal_statistics",
address=address,
years_back=years_back,
property_type=property_type,
min_rooms=min_rooms,
max_rooms=max_rooms,
)
try: try:
# Get all deals for the address # Get all deals for the address
deals = client.find_recent_deals_for_address(address, years_back) deals = client.find_recent_deals_for_address(address, years_back)
@@ -974,6 +1044,12 @@ def get_market_activity_metrics(address: str, years_back: int = 2, radius_meters
- Investment potential analysis - Investment potential analysis
- Price appreciation and volatility - Price appreciation and volatility
""" """
log_mcp_call(
"get_market_activity_metrics",
address=address,
years_back=years_back,
radius_meters=radius_meters,
)
try: try:
# Get deals for the address # Get deals for the address
deals = client.find_recent_deals_for_address(address, years_back, radius_meters) deals = client.find_recent_deals_for_address(address, years_back, radius_meters)