Custom MCP Connector Search Issue

Hello, I successfully connected my custom Google Ads connector, but the search results are not good. I understand that both search and fetch are mandatory for building MCP connectors, so I developed the code accordingly and connected it. However, I’m not getting the expected results—only dummy data is returned by ChatGPT, even though search and fetch work correctly locally and on Replit.

import os
import logging
from typing import Dict, Any, List
from fastmcp.server import FastMCP
from pydantic import BaseModel

logging.basicConfig(level=logging.INFO)

public_url = “https://gads-server-replit2844.replit.app

GOOGLE_ADS_DEVELOPER_TOKEN = os.environ.get(“GOOGLE_ADS_DEVELOPER_TOKEN”)
GOOGLE_ADS_CLIENT_ID = os.environ.get(“GOOGLE_ADS_CLIENT_ID”)
GOOGLE_ADS_CLIENT_SECRET = os.environ.get(“GOOGLE_ADS_CLIENT_SECRET”)
GOOGLE_ADS_REFRESH_TOKEN = os.environ.get(“GOOGLE_ADS_REFRESH_TOKEN”)
GOOGLE_ADS_CUSTOMER_ID = os.environ.get(“GOOGLE_ADS_CUSTOMER_ID”)
GOOGLE_ADS_LOGIN_CUSTOMER_ID = os.environ.get(“GOOGLE_ADS_LOGIN_CUSTOMER_ID”) # MCC ID

app = FastMCP(
name=“Google Ads Connector”,
instructions=“Connects to Google Ads API to search campaigns, keywords, and fetch detailed performance data.”,
)

def get_google_ads_client():
“”“Initialize and return Google Ads API client”“”
try:
from google.ads.googleads.client import GoogleAdsClient

    
    config = {
        "developer_token": GOOGLE_ADS_DEVELOPER_TOKEN,
        "client_id": GOOGLE_ADS_CLIENT_ID,
        "client_secret": GOOGLE_ADS_CLIENT_SECRET,
        "refresh_token": GOOGLE_ADS_REFRESH_TOKEN,
        "use_proto_plus": True,  # Required as of v14.0.0
    }

    # Add login customer ID if provided (for MCC access)
    if GOOGLE_ADS_LOGIN_CUSTOMER_ID:
        config["login_customer_id"] = GOOGLE_ADS_LOGIN_CUSTOMER_ID

    # Validate required credentials
    missing_creds = [k for k, v in config.items() if not v and k not in ["use_proto_plus", "login_customer_id"]]
    if missing_creds:
        raise ValueError(f"Missing Google Ads credentials: {missing_creds}")

    return GoogleAdsClient.load_from_dict(config)

except ImportError:
    raise ImportError(
        "Google Ads library not installed. Run: pip install google-ads"
    )
except Exception as e:
    logging.error(f"Failed to initialize Google Ads client: {e}")
    raise

def build_campaign_query(search_terms: str = None) → str:
“”“Build GAQL query for campaign search”“”

base_query = “”"
SELECT
campaign.id,
campaign.name,
campaign.status
FROM campaign
LIMIT 10
“”"
return base_query

def build_campaign_detail_query(campaign_id: str) → str:
“”“Build GAQL query for specific campaign details”“”
return f"“”
SELECT
campaign.id,
campaign.name,
campaign.status,
campaign.advertising_channel_type,
campaign.start_date,
campaign.end_date,
campaign_budget.amount_micros,
metrics.impressions,
metrics.clicks,
metrics.ctr,
metrics.cost_micros,
metrics.conversions,
metrics.average_cpc,
metrics.average_cpm
FROM campaign
WHERE campaign.id = {campaign_id}
“”"

def micros_to_currency(micros: int) → float:
“”“Convert micros to currency format”“”
return micros / 1_000_000 if micros else 0

def format_campaign_data(row) → Dict[str, Any]:
“”“Format campaign data from API response”“”
campaign = row.campaign

return {
    "id": str(campaign.id),
    "name": campaign.name,
    "status": campaign.status.name
}

def format_campaign_details(row) → Dict[str, Any]:
“”“Format detailed campaign data from API response”“”
campaign = row.campaign
metrics = row.metrics
budget = getattr(row, ‘campaign_budget’, None)

details = format_campaign_data(row)

# Add detailed information
details.update({
    "start_date": campaign.start_date if hasattr(campaign, 'start_date') else None,
    "end_date": campaign.end_date if hasattr(campaign, 'end_date') else None,
    "budget": {
        "daily_budget": f"${micros_to_currency(budget.amount_micros):.2f}" if budget else "Not available"
    },
    "detailed_metrics": {
        "average_cpc": f"${micros_to_currency(metrics.average_cpc):.2f}" if metrics.average_cpc else "$0.00",
        "average_cpm": f"${micros_to_currency(metrics.average_cpm):.2f}" if metrics.average_cpm else "$0.00"
    }
})

return details

@app.tool()
async def search(query: str) → Dict[str, Any]:
“”"
Search Google Ads campaigns, keywords, or performance data.

Args:
    query: Search term for Google Ads data (e.g., "campaign performance", "keyword metrics", "brand campaigns")

Returns:
    Dictionary containing search results with campaign data
"""
try:
    # Check if Google Ads credentials are configured
    if not all([GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_CLIENT_ID, 
               GOOGLE_ADS_CLIENT_SECRET, GOOGLE_ADS_REFRESH_TOKEN, 
               GOOGLE_ADS_CUSTOMER_ID]):
        return {
            "error": "Google Ads API credentials not configured",
            "message": "Please set up your Google Ads API credentials in environment variables",
            "required_variables": [
                "GOOGLE_ADS_DEVELOPER_TOKEN",
                "GOOGLE_ADS_CLIENT_ID", 
                "GOOGLE_ADS_CLIENT_SECRET",
                "GOOGLE_ADS_REFRESH_TOKEN",
                "GOOGLE_ADS_CUSTOMER_ID",
                "GOOGLE_ADS_LOGIN_CUSTOMER_ID (for MCC access)"
            ]
        }

    try:
        # Initialize Google Ads client
        client = get_google_ads_client()
        service = client.get_service("GoogleAdsService")

        # Build and execute query
        gaql_query = build_campaign_query(query)
        response = service.search(
            customer_id=GOOGLE_ADS_CUSTOMER_ID,
            query=gaql_query
        )

        # Process results
        campaigns = []
        for row in response:
            campaign_data = format_campaign_data(row)
            campaigns.append(campaign_data)

            # Optional: If search terms provided, we could filter here
            # But for now, let's return all campaigns

        return {
            "query": query,
            "total_results": len(campaigns),
            "campaigns": campaigns,
            "customer_id": GOOGLE_ADS_CUSTOMER_ID
        }

    except Exception as api_error:
        logging.error(f"Google Ads API error: {api_error}")
        return {
            "error": "Google Ads API request failed",
            "message": str(api_error),
            "query": query
        }

except Exception as e:
    logging.error(f"Search error: {e}")
    return {
        "error": "Search request failed",
        "message": str(e),
        "query": query
    }

@app.tool()
async def fetch(id: str) → Dict[str, Any]:
“”"
Fetch detailed information about a specific Google Ads campaign.

Args:
    id: The campaign ID to fetch detailed information for

Returns:
    Dictionary containing detailed campaign information
"""
try:
    # Check if Google Ads credentials are configured
    if not all([GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_CLIENT_ID, 
               GOOGLE_ADS_CLIENT_SECRET, GOOGLE_ADS_REFRESH_TOKEN, 
               GOOGLE_ADS_CUSTOMER_ID]):
        return {
            "error": "Google Ads API credentials not configured",
            "message": "Please set up your Google Ads API credentials in environment variables"
        }

    try:
        # Initialize Google Ads client
        client = get_google_ads_client()
        service = client.get_service("GoogleAdsService")

        # Build and execute query for specific campaign
        gaql_query = build_campaign_detail_query(id)
        response = service.search(
            customer_id=GOOGLE_ADS_CUSTOMER_ID,
            query=gaql_query
        )

        # Process result
        for row in response:
            return format_campaign_details(row)

        # If no results found
        return {
            "error": "Campaign not found",
            "message": f"No campaign found with ID: {id}",
            "campaign_id": id
        }

    except Exception as api_error:
        logging.error(f"Google Ads API error: {api_error}")
        return {
            "error": "Google Ads API request failed",
            "message": str(api_error),
            "campaign_id": id
        }

except Exception as e:
    logging.error(f"Fetch error: {e}")
    return {
        "error": "Fetch request failed",
        "message": str(e),
        "campaign_id": id
    }

@app.tool()
async def health_check() → Dict[str, Any]:
“”"
Check the health and configuration status of the Google Ads connector.

Returns:
    Dictionary containing health status and configuration info
"""
config_status = {
    "GOOGLE_ADS_DEVELOPER_TOKEN": "✓ Set" if GOOGLE_ADS_DEVELOPER_TOKEN else "✗ Missing",
    "GOOGLE_ADS_CLIENT_ID": "✓ Set" if GOOGLE_ADS_CLIENT_ID else "✗ Missing",
    "GOOGLE_ADS_CLIENT_SECRET": "✓ Set" if GOOGLE_ADS_CLIENT_SECRET else "✗ Missing", 
    "GOOGLE_ADS_REFRESH_TOKEN": "✓ Set" if GOOGLE_ADS_REFRESH_TOKEN else "✗ Missing",
    "GOOGLE_ADS_CUSTOMER_ID": "✓ Set" if GOOGLE_ADS_CUSTOMER_ID else "✗ Missing",
    "GOOGLE_ADS_LOGIN_CUSTOMER_ID": "✓ Set" if GOOGLE_ADS_LOGIN_CUSTOMER_ID else "✗ Missing (needed for MCC)"
}

try:
    # Try to import Google Ads library
    from google.ads.googleads.client import GoogleAdsClient
    library_status = "✓ Installed"
except ImportError:
    library_status = "✗ Not installed - Run: pip install google-ads"

return {
    "status": "healthy" if all([GOOGLE_ADS_DEVELOPER_TOKEN, GOOGLE_ADS_CLIENT_ID, 
                               GOOGLE_ADS_CLIENT_SECRET, GOOGLE_ADS_REFRESH_TOKEN, 
                               GOOGLE_ADS_CUSTOMER_ID]) else "configuration_needed",
    "google_ads_library": library_status,
    "configuration": config_status,
    "server_url": public_url
}

if name == “main”:

app.run(transport=“streamable-http”, host=“0.0.0.0”, port=8000, path=“/mcp”)