mcp-google-ads
repository·main·Indexed 20 days ago
https://github.com/cohnen/mcp-google-adsA Model Context Protocol (MCP) server that integrates the Google Ads API with AI assistants like Claude and Cursor. It enables natural language querying and analysis of advertising data through tools such as list_accounts, execute_gaql_query, get_campaign_performance, get_ad_performance, and run_gaql. The server supports both OAuth 2.0 and Service Account authentication methods for accessing Google Ads data.
What's inside mcp-google-ads
- Google Ads MCP is a Model Context Protocol (MCP) server that connects Google Ads with AI assistants like Claude or code editors like Cursor. It allows users to analyze advertising data, manage accounts, track campaign performance, and perform keyword/ad analysis using natural language. The tool acts as a bridge between the AI and the Google Ads API, enabling the AI to fetch data, visualize metrics, and provide actionable insights.
Understand Google Ads Query Language (GAQL) structure
mainGAQL is used to retrieve resources, attributes, segments, and metrics from the Google Ads API. A standard query follows this structure:
SELECT <field_1>, <field_2> FROM <resource> WHERE <condition> ORDER BY <field> [ASC|DESC] LIMIT <number>Field Categories
- RESOURCE: The primary entity in the
FROMclause (e.g.,campaign,ad_group). - ATTRIBUTE: Properties of a resource (e.g.,
campaign.id). - SEGMENT: Fields that segment results (e.g.,
segments.date,segments.device). - METRIC: Performance data that does not segment queries (e.g.,
metrics.clicks).
SELECT campaign.id, campaign.name, metrics.impressions, segments.device FROM campaign- RESOURCE: The primary entity in the
Expose data using Resources
mainResources are used to expose data to LLMs (similar to GET endpoints in REST). They should provide data without significant computation or side effects. FastMCP supports both static and dynamic resources using templates.
Static Resource:
@mcp.resource("config://app") def get_config() -> str: """Static configuration data""" return "App configuration here"Dynamic Resource (with parameters):
@mcp.resource("users://{user_id}/profile") def get_user_profile(user_id: str) -> str: """Dynamic user data""" return f"Profile data for user {user_id}"@mcp.resource("users://{user_id}/profile") def get_user_profile(user_id: str) -> str: return f"Profile data for user {user_id}"Access MCP capabilities via Context
mainThe
Contextobject allows tools and resources to interact with the MCP environment. To use it, include a parameter annotated withfastmcp.Contextin your function signature.Capabilities provided by Context:
- Progress reporting:
ctx.report_progress(current, total) - Logging:
ctx.debug(),ctx.info(),ctx.warning(),ctx.error() - Resource access:
await ctx.read_resource(uri) - Metadata:
ctx.request_id,ctx.client_id
Example usage:
from fastmcp import FastMCP, Context @mcp.tool() async def long_task(files: list[str], ctx: Context) -> str: for i, file in enumerate(files): ctx.info(f"Processing {file}") await ctx.report_progress(i, len(files)) data = await ctx.read_resource(f"file://{file}") return "Processing complete"- Progress reporting:
Define interaction patterns with Prompts
mainPrompts are reusable templates that help LLMs interact with your server effectively. They can be simple strings or structured sequences of messages.
Simple String Prompt:
@mcp.prompt() def review_code(code: str) -> str: return f"Please review this code:\n\n{code}"Structured Message Prompt:
from fastmcp.prompts.base import UserMessage, AssistantMessage @mcp.prompt() def debug_error(error: str) -> list[Message]: return [ UserMessage("I'm seeing this error:"), UserMessage(error), AssistantMessage("I'll help debug that. What have you tried so far?") ]Specify Custom Server Object Names
mainBy default, FastMCP commands look for a server object named
mcp,app, orserverin your file. If you use a different name or have multiple servers in one file, you must use thefilename.py:object_namesyntax.# If your object is named 'my_custom_server' in server.py fastmcp run server.py:my_custom_serverExecute actions using Tools
mainTools allow LLMs to take actions through your server (similar to POST endpoints). They are intended to perform computation or produce side effects. You can use standard Python types,
asyncfunctions, or complexpydanticmodels for input validation.Simple Tool:
@mcp.tool() def calculate_bmi(weight_kg: float, height_m: float) -> float: """Calculate BMI""" return weight_kg / (height_m ** 2)Async Tool (HTTP request):
import httpx @mcp.tool() async def fetch_weather(city: str) -> str: async with httpx.AsyncClient() as client: response = await client.get(f"https://api.weather.com/{city}") return response.textComplex Input with Pydantic:
from pydantic import BaseModel, Field from typing import Annotated class ShrimpTank(BaseModel): class Shrimp(BaseModel): name: Annotated[str, Field(max_length=10)] shrimp: list[Shrimp] @mcp.tool() def name_shrimp(tank: ShrimpTank, extra_names: Annotated[list[str], Field(max_length=10)]) -> list[str]: return [shrimp.name for shrimp in tank.shrimp] + extra_names@mcp.tool() def calculate_bmi(weight_kg: float, height_m: float) -> float: return weight_kg / (height_m ** 2)Handle images with the Image class
mainFastMCP provides an
Imageclass that automatically handles image data, conversion, and MIME types. Images can be returned by both tools and resources.Creating a thumbnail:
from fastmcp import FastMCP, Image from PIL import Image as PILImage @mcp.tool() def create_thumbnail(image_path: str) -> Image: img = PILImage.open(image_path) img.thumbnail((100, 100)) return Image(data=img.tobytes(), format="png")Loading from disk:
@mcp.tool() def load_image(path: str) -> Image: return Image(path=path)from fastmcp import Image @mcp.tool() def load_image(path: str) -> Image: return Image(path=path)Use the Context object in tools and resources
mainThe
Contextobject provides access to MCP capabilities during a request. To use it, add a parameter to your tool or resource function with theContexttype annotation. The parameter name can be anything.Capabilities provided by
Context:- Logging:
ctx.info(),ctx.debug(),ctx.warning(),ctx.error(). - Progress Reporting:
ctx.report_progress(progress, total). - Resource Access:
ctx.read_resource(uri). - Metadata: Access
ctx.request_idandctx.client_id. - Server Access: Access the underlying
FastMCPinstance viactx.fastmcpor theRequestContextviactx.request_context(only available during an active request).
@server.tool() def my_tool(x: int, ctx: Context) -> str: # Log messages to the client ctx.info(f"Processing {x}") ctx.debug("Debug info") ctx.warning("Warning message") ctx.error("Error message") # Report progress ctx.report_progress(50, 100) # Access resources data = ctx.read_resource("resource://data") # Get request info request_id = ctx.request_id client_id = ctx.client_id return str(x)- Logging:
Quickstart: Create and run a FastMCP server
mainYou can create a simple MCP server by importing
FastMCPand using decorators to define tools and resources.1. Define your server:
from fastmcp import FastMCP mcp = FastMCP("Demo") @mcp.tool() def add(a: int, b: int) -> int: """Add two numbers""" return a + b @mcp.resource("greeting://{name}") def get_greeting(name: str) -> str: """Get a personalized greeting""" return f"Hello, {name}!"2. Run or Install:
- To install the server in Claude Desktop:
fastmcp install server.py - To test the server with the MCP Inspector:
fastmcp dev server.py
- To install the server in Claude Desktop:
Execute FastMCP Server Directly
mainFor advanced use cases like custom deployments or running without Claude, you can execute the server directly.
Important: When running directly, FastMCP ignores the
dependencieslist provided in theFastMCPconstructor. You are responsible for ensuring all required dependencies are available in your current environment.To run a server, ensure your script includes the
mcp.run()call in the entry point.from fastmcp import FastMCP mcp = FastMCP("My App") if __name__ == "__main__": mcp.run()Run via FastMCP CLI
fastmcp run server.py
Run via Python or uv
python server.py uv run python server.py
Install Google Ads MCP locally
mainFollow these steps to install the project and its dependencies:
Clone the repository:
git clone https://github.com/ixigo/mcp-google-ads.git cd mcp-google-adsCreate and activate a virtual environment:
# Using uv (recommended) pip install uv uv venv .venv source .venv/bin/activate # Mac/Linux # OR .venv\Scripts\activate # WindowsInstall dependencies:
uv pip install -r requirements.txt # OR pip install -r requirements.txt
git clone https://github.com/ixigo/mcp-google-ads.git cd mcp-google-ads uv venv .venv source .venv/bin/activate uv pip install -r requirements.txt