A Google search MCP server is a small program that lets an AI agent search Google and read the results. You run it on your computer. Then you point Claude Desktop, Cursor or another MCP client at it, and the agent gets a google_search tool it can call whenever it needs fresh facts.
Below is a complete one in about 75 lines of Python. It uses the official MCP SDK and a SERP API, and it works with any MCP client.
What is MCP, in plain words?
MCP, the Model Context Protocol, is an open standard for connecting AI apps to outside tools and data. Anthropic introduced it in November 2024. The official docs compare it to a USB-C port for AI apps: one plug that fits many devices.
There are two sides:
- The server offers tools. Ours offers one tool,
google_search. - The client is the AI app, such as Claude Desktop, Cursor or Claude Code. The model reads each tool’s name and description and decides when to call it.
In this setup, the client starts the server as a small background program. They talk over standard input and output, which MCP calls the stdio transport. Nothing is exposed to the internet.
Why not use the agent’s built-in web search?
Claude and ChatGPT can already search the web. That is fine for quick answers. It falls short when you need what Google shows:
- You cannot pick the country or device. Rankings in London on mobile differ from New York on desktop.
- You do not see the page. No positions, no AI Overview, no People Also Ask.
- Google’s own API is going away. The Custom Search JSON API is closed to new customers and shuts down on January 1, 2027. Our guide to the Custom Search API shutdown covers the options.
- Scraping Google yourself breaks. A script on your laptop hits captchas within minutes. We explain why in how to scrape Google search results.
A SERP API fetches the real results page from the country and device you choose, and returns it as JSON. The MCP server is the thin layer that hands that JSON to the agent.
What you need
- Python 3.10 or newer and uv, a fast Python package manager.
- An MCP client: Claude Desktop, Cursor, Claude Code, or any other.
- A SERP API key. This guide uses Serplify’s
POST /v1/serp/searchendpoint. New accounts get $1 of free credit, about 200 searches.
Step 1: Create the project
uv init google-search-mcp
cd google-search-mcp
uv add "mcp[cli]"
That installs the official MCP Python SDK. We tested this guide with version 2.3.0. Version 2 renamed the main class to MCPServer, so older tutorials that import FastMCP will not run on it.
Step 2: Write the server
Create server.py and paste this in:
import asyncio
import os
import httpx2
from mcp.server import MCPServer
from mcp.server.mcpserver.exceptions import ToolError
API = "https://api.serplify.io"
KEY = os.environ["SERPLIFY_KEY"]
mcp = MCPServer("google-search")
@mcp.tool()
async def google_search(
query: str,
location_code: int = 2840,
language: str = "en",
device: str = "desktop",
) -> dict:
"""Search Google and return the live first page of results.
Use it for recent events, prices, rankings, or anything you are unsure of.
Args:
query: The search, typed the way a person would type it.
location_code: Google location code. 2840 = United States, 2826 = United Kingdom.
language: Language code, such as "en" or "de".
device: "desktop" or "mobile".
"""
body = {
"keyword": query,
"location": {"code": location_code},
"language": {"code": language},
"device": device,
"depth": 10,
}
headers = {"Authorization": f"Bearer {KEY}"}
async with httpx2.AsyncClient(base_url=API, headers=headers, timeout=300) as http:
res = await http.post("/v1/serp/search", json=body)
# A slow search comes back as HTTP 202 with a task to poll.
for _ in range(20):
if res.status_code != 202:
break
await asyncio.sleep(3)
res = await http.get(res.json()["data"]["status_url"])
payload = res.json()
if res.status_code != 200:
message = payload.get("error", {}).get("message", "still running, try again")
raise ToolError(f"Search failed ({res.status_code}): {message}")
return summarize(payload["data"])
def summarize(data: dict) -> dict:
"""Keep what an agent needs from the page and drop the rest."""
page = {"query": data["keyword"], "ai_overview": None, "results": [], "people_also_ask": []}
for item in data["items"]:
if item["type"] == "organic":
page["results"].append({
"position": item["rank_group"],
"title": item["title"],
"url": item["url"],
"snippet": item.get("description"),
})
elif item["type"] == "ai_overview":
parts = item.get("items") or []
page["ai_overview"] = {
"text": "\n".join(p.get("text") or "" for p in parts),
"sources": [ref["url"] for ref in item.get("references") or []],
}
elif item["type"] == "people_also_ask":
page["people_also_ask"] = [q["title"] for q in item.get("items") or []]
return page
if __name__ == "__main__":
mcp.run(transport="stdio")
What each part does:
@mcp.tool()turns the function into a tool. The SDK builds the input schema from the type hints. The docstring becomes the description the model reads, so write it for the model.- The request body follows the API docs: keyword, location, language and device.
depth: 10asks for the first page only. The price is per page either way, and a smaller page loads faster. - The polling loop handles slow searches. If a live search cannot finish in time, the API answers
HTTP 202with astatus_url. The loop checks it every 3 seconds for up to a minute. Checking is free. ToolErrorsends a readable message, like “Missing or invalid API key”, back to the model. In SDK version 2, other errors reach the model only as a generic failure.summarize()keeps three things: organic results, the AI Overview with its sources, and People Also Ask questions. A full page can hold dozens of block types. Sending all of them wastes the model’s context.
One rule matters for every stdio server: never use print(). Standard output carries the protocol messages, and a stray print breaks the connection. Use the logging module, which writes to standard error.
Step 3: Connect it to Claude Desktop
Open the Claude Desktop config file. Create it if it does not exist.
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Add the server:
{
"mcpServers": {
"google-search": {
"command": "uv",
"args": ["--directory", "/ABSOLUTE/PATH/TO/google-search-mcp", "run", "server.py"],
"env": { "SERPLIFY_KEY": "live_your_key_here" }
}
}
}
Use the full path to your project folder. Save the file and restart Claude Desktop. If it cannot find uv, put the full path from which uv in the command field.
Step 4: Connect Cursor or Claude Code
Cursor reads the same JSON shape. Put it in ~/.cursor/mcp.json for every project, or .cursor/mcp.json for one. If the tool does not appear, open the Output panel and pick “MCP Logs”.
Claude Code adds it with one command:
claude mcp add --env SERPLIFY_KEY=live_your_key_here --transport stdio google-search \
-- uv --directory /ABSOLUTE/PATH/TO/google-search-mcp run server.py
Keep your key out of code you commit. The env field and the --env flag pass it to the server at start.
Step 5: Try it
Ask the agent something it cannot know from training. For example: “Search Google for search api for ai agents. Which sites rank first, and what does the AI Overview cite?” It should call google_search and answer from the page.
Here is what summarize() made of the real US desktop page for that query on October 9, 2026. We trimmed it to two results, three sources and four questions:
{
"query": "search api for ai agents",
"ai_overview": {
"text": "A web search API for AI agents evaluates a natural language query from an autonomous workflow and returns clean, machine-readable data ...",
"sources": [
"https://tavily.com/",
"https://www.firecrawl.dev/glossary/web-search-apis/web-search-tool-ai-agents",
"https://www.vellum.ai/blog/best-web-search-apis-and-mcps-for-ai-agents"
]
},
"results": [
{
"position": 1,
"title": "Tavily",
"url": "https://tavily.com/",
"snippet": "Tavily is the real-time search engine for AI agents ..."
},
{
"position": 2,
"title": "What's the best tool/API for web search in an agentic stack?",
"url": "https://www.reddit.com/r/AI_Agents/comments/1pf9avo/whats_the_best_toolapi_for_web_search_in_an/",
"snippet": "I'm building an agentic stack where one component needs to run real web searches ..."
}
],
"people_also_ask": [
"Which search API is best for AI agents?",
"Do AI agents use APIs?",
"What is the best web search tool for AI agents?",
"Is there a free AI agent API available?"
]
}
That page had nine organic results and an AI Overview with 16 sources. The agent gets all of it as compact JSON. To pull more block types, like videos or the local pack, add branches to summarize(). Our post on how we parse SERP features into JSON lists the shapes.
What it costs
Each successful search costs $0.005, so 1,000 searches cost $5. A failed or blocked search costs nothing. If your agent runs 300 searches a day, that is $1.50 a day.
There is no plan or monthly fee. The $1 of free credit covers about 200 searches, which is plenty to test the server. Our Google SERP API page has the full price and feature list. For a walkthrough of the API itself, see how to use the Serplify SERP API.
Other ways to give an agent web search
A Google results page is not always what an agent needs. These are the main options as of October 2026.
| Option | Where results come from | Best when |
|---|---|---|
| Built-in web search in Claude or ChatGPT | The app’s own search provider | You only need answers, not Google’s page |
| Brave Search MCP server (official, from Brave) | Brave’s own index | You want a ready-made server and do not need Google |
| Exa or Tavily MCP servers | AI-first search engines that also return page text | Research and RAG agents that need page content |
| Google Custom Search JSON API | A Google custom search engine | Not for new projects: closed to new customers, ends January 1, 2027 |
| Community servers that scrape google.com | Google, fetched from your own IP | Hobby use; they break on captchas |
| Your own server plus a SERP API (this guide) | The real Google page, by country and device | You need rankings, AI Overviews or People Also Ask |
Pick by the question your agent answers. “What does Google show for this keyword?” needs Google’s page. “What do sources say about this topic?” can use any good index.
Frequently asked questions
Is there an official Google Search MCP server?
Not for public web results, as of October 2026. Google's official MCP servers, announced in December 2025, cover services like Maps, BigQuery and Compute Engine. To give an agent the public Google results page, you need a SERP API behind your own MCP server, or a different search engine.
Which search API is best for AI agents?
It depends on what the agent needs. For what Google shows, including rankings, AI Overviews and People Also Ask, use a SERP API. For page text to feed a RAG app, AI-first engines like Exa or Tavily return content directly. For simple answers, the built-in web search in Claude or ChatGPT may be enough.
Is there a free web search API for AI agents?
Most search APIs have a free tier or trial credit. Serplify gives $1 of free credit at signup, which covers about 200 Google searches. Google's Custom Search JSON API had 100 free queries a day, but it is closed to new customers and shuts down on January 1, 2027.
Can I write the server in TypeScript instead?
Yes. The official TypeScript SDK works the same way: create a server, register a tool with an input schema, and connect it over stdio. The API request and the client config stay the same.
Sources and further reading
- Model Context Protocol: What is MCP? modelcontextprotocol.io
- Model Context Protocol: Build an MCP server modelcontextprotocol.io
- MCP Python SDK documentation py.sdk.modelcontextprotocol.io
- Anthropic: Introducing the Model Context Protocol (November 2024) anthropic.com
- Serplify docs: Live search docs.serplify.io
- Google for Developers: Custom Search JSON API overview developers.google.com
- Cursor docs: Model Context Protocol cursor.com