Skip to main content
Glama
jspv

Google Search MCP Server

by jspv
README.md
# Google Search MCP Server

A Model Context Protocol (MCP) server that provides Google Custom Search functionality.

**🎯 This repository demonstrates 5 different deployment patterns** for the same MCP functionality:

1. **[stdio Mode](#1-stdio-mode-default-mcp)** - Standard MCP over stdin/stdout for local development and MCP client integration
2. **[HTTP over SSE](#2-http-over-sse-mcp-transport)** - MCP HTTP transport using Server‑Sent Events (browser-friendly)
3. **[HTTP Streamable](#3-http-streamable-non-sse)** - MCP Streamable HTTP transport (non‑SSE)
4. **[AWS Lambda + AgentCore Gateway](#4-aws-lambda--agentcore-gateway)** - Serverless deployment with OAuth authentication
5. **[Containerized MCP Service](#5-containerized-mcp-service)** - Docker containers deployed to ECS Fargate for scalable cloud deployment

## Installation

Clone the repository and install dependencies:

```bash
git clone https://github.com/jspv/google-search-mcp.git
cd google-search-mcp
uv sync
```

## Project structure

- `server.py` / `server_http.py` / `server_http_stream.py` — MCP servers (stdio, HTTP, streaming)
- `lambda_handler.py` — AWS Lambda adapter for MCP stdio server
- `Dockerfile.mcp` — Container image for HTTP/streaming MCP service
- `deploy/` — legacy deployment assets (use `deploy_aws_agentcore_auth0/`)
- `deploy_aws_agentcore_auth0/` — canonical Auth0 + AgentCore Gateway deploy scripts and templates
   - `build_zip.sh` — build Lambda ZIP
   - `deploy_lambda.sh` — deploy Lambda via CloudFormation
   - `AGENTCORE_GATEWAY_CHECKLIST.md` — complete Gateway (Lambda + Cognito) integration checklist
   
   - `deploy_gateway.sh` — attempt AgentCore setup via CLI
   - `gen_tool_schema.sh` — generate MCP tool schema (uses Python stdio client)
   - `cloudformation-*.yaml` — infrastructure templates
   - `README-*.md` — deployment-specific docs
- `scripts/` — developer/CI utilities
   - `dump_tool_schema.py` — dump schema from an MCP server over stdio
- `dist/` — build artifacts and generated outputs
   - `schema/tool-schema.json` — generated tool schema for AgentCore
   - `google_search_mcp_lambda.zip` — built Lambda package
- `tests/` — unit and integration tests


### Optional Dependencies

Install additional dependencies based on your deployment needs:

```bash
# For HTTP/streaming modes
uv sync --extra http

# For AWS Lambda deployment
uv sync --extra lambda

# For containerized deployments (ECS/Fargate)
uv sync --extra container

# For AWS (both Lambda and container)
uv sync --extra aws

# For development
uv sync --extra dev

# Install multiple extras
uv sync --extra http --extra aws --extra dev
```

## Configuration

This server uses [Dynaconf](https://www.dynaconf.com/) for configuration management, supporting both `.env` files and environment variables.

### Setup

1. Copy the example environment file:
   ```bash
   cp .env.example .env
   ```

2. Edit `.env` and add your Google API credentials:
   ```bash
   GOOGLE_API_KEY=your_actual_api_key_here
   GOOGLE_CX=your_custom_search_engine_id_here
   ```

### Environment Variable Override

Environment variables will **override** `.env` file values when both are present. This allows for flexible deployment scenarios:

- **Development**: Use `.env` file for local development
- **Production**: Use environment variables for production deployment
- **CI/CD**: Environment variables can override defaults for testing

#### Example:

If your `.env` file contains:
```bash
GOOGLE_API_KEY=dev_key_from_file
```

And you set an environment variable:
```bash
export GOOGLE_API_KEY=prod_key_from_env
```

The server will use `prod_key_from_env` (environment variable takes precedence).

### Required Configuration

- `GOOGLE_API_KEY`: Your Google Custom Search API key
- `GOOGLE_CX`: Your Custom Search Engine ID

Get these from:
- API Key: [Google Cloud Console](https://console.developers.google.com/)
- Search Engine ID: [Google Custom Search](https://cse.google.com/cse/all)

### Optional Configuration

- `ALLOW_DOMAINS` (`GOOGLE_ALLOW_DOMAINS` env var): Comma-separated list of allowed domains (e.g., `example.com, docs.python.org`).
   When set, results outside these domains are filtered out.

- Logging:
   - `LOG_QUERIES` (`GOOGLE_LOG_QUERIES`): Enable logging of query hash, timing, and key params.
   - `LOG_QUERY_TEXT` (`GOOGLE_LOG_QUERY_TEXT`): Also log full query text (off by default).
   - `LOG_LEVEL` (`GOOGLE_LOG_LEVEL`): Set logging level (e.g., `INFO`, `DEBUG`).
   - `LOG_FILE` (`GOOGLE_LOG_FILE`): Optional path to also write logs to a file (stderr remains enabled).

## Usage

This project provides 5 different deployment patterns for the same Google Search MCP functionality:

### 1. stdio Mode (Default MCP)

Standard MCP server for local development and integration with MCP clients:

```bash
# Run via uv (recommended)
uv run python -m server

# Or direct execution
python server.py

# Run via uvx (no activation, from any folder)
uvx --from /Users/justin/src/google_search_mcp google-search-mcp

# Run via pipx (isolated, globally available)
pipx install /Users/justin/src/google_search_mcp
google-search-mcp
```

Communicates over stdin/stdout using the standard MCP protocol.

### 2. HTTP over SSE (MCP transport)

MCP over HTTP using Server‑Sent Events (SSE). This exposes the standard MCP HTTP endpoints used by browser clients.

```bash
# Install HTTP extras and run
uv sync --extra http
uv run python -m server_http

# Or via console script (if installed)
uv run google-search-mcp-http

# With custom host/port
HOST=0.0.0.0 PORT=8000 uv run python -m server_http
```

Available MCP endpoints (not a custom REST API):
- `GET /sse` — SSE connection for events
- `POST /messages` — MCP message handling

Notes:
- CORS enabled by default (customize with `CORS_ORIGINS`).
- Same configuration as stdio mode (`GOOGLE_API_KEY`, `GOOGLE_CX`, etc.).

### 3. HTTP Streamable (non‑SSE)

MCP Streamable HTTP transport for clients that don’t use SSE.

```bash
# Start the Streamable HTTP MCP server
uv sync --extra http
uv run python -m server_http_stream

# Or via console script (if installed)
uv run google-search-mcp-stream

# Custom host/port
HOST=0.0.0.0 PORT=8000 uv run python -m server_http_stream
```

Notes:
- Not a REST interface. Use an MCP client that supports the Streamable HTTP transport.
- CORS behavior matches the SSE app and is configurable via `CORS_ORIGINS`.

### 4. AWS Lambda + AgentCore Gateway

**Prerequisites**: 
```bash
# Install Lambda dependencies
uv sync --extra lambda

# Configure AWS credentials
aws configure
```

Deploy to AWS Lambda with Bedrock AgentCore Gateway integration:

```bash
# Build and deploy
./deploy_aws_agentcore_auth0/build_zip.sh        # Cross-platform build
./deploy_aws_agentcore_auth0/deploy_lambda.sh    # Deploy via CloudFormation
./deploy_aws_agentcore_auth0/deploy_gateway.sh # Setup AgentCore Gateway

# Test the deployment
python3 deploy_aws_agentcore_auth0/test_gateway_auth0.py https://your-gateway-url.amazonaws.com client-id client_secret https://your-domain.auth0.com [audience]
```

Features:
- JSON-RPC 2.0 protocol with OAuth authentication
- Serverless execution with environment variable inheritance
- Integrated with AWS Bedrock AgentCore ecosystem

### 5. Containerized MCP Service

**Prerequisites**:
```bash
# Install container dependencies (for ECR/ECS deployment)
uv sync --extra container

# Configure Docker and AWS
docker --version
aws configure
```

**Local Testing**:
```bash
# Build container
docker build -f Dockerfile.mcp -t google-search-mcp .

# Run locally
docker run -p 8000:8000 --env-file .env -e MCP_MODE=http-stream google-search-mcp
```

**Deploy to AWS ECS Fargate**:
```bash
# Deploy to ECS Fargate
./deploy/deploy_mcp_container.sh google-search-mcp us-east-1 ecs-fargate
```

Features:
- Multi-mode container supporting stdio, HTTP, and streaming
- Scalable deployment via ECS Fargate
- Environment variable configuration
- Health checks and monitoring

**Note**: AgentCore Runtime uses preview SDK and requires manual configuration as APIs are not publicly available.

### Configuration Notes

All deployment patterns use the same configuration:
- Set `DYNACONF_DOTENV_PATH` for .env loading when needed
- Environment variables override settings.toml values
- Logging configuration applies across all modes

## Quick Start

This project uses httpx with HTTP/2 support enabled. The dependency is declared as `httpx[http2]` and will install the `h2` package automatically.

### Using uv (recommended)

```bash
# Install dependencies
uv sync

# Create and configure environment
cp .env.example .env
$EDITOR .env

# Run tests (optional sanity check)
uv run pytest -q

# Start the MCP server (stdio mode)
uv run python server.py
```

### Quick Test (no MCP client required)

Test the search function directly:

```bash
uv run python -c 'import asyncio, server; print(asyncio.run(server.search("site:python.org httpx", num=2, safe="off")))'
```

Note: `safe` must be `off` or `active`, and `num` is clamped to maximum of 10 per Google CSE limits.

### Logging behavior

If `LOG_QUERIES` is enabled, the server will write a single line per request to stdout containing:
- q_hash (short, non-reversible hash of the query), dt_ms (latency), num, start, safe, and endpoint (cse/siterestrict)
- If `LOG_QUERY_TEXT` is true, it also includes the full `q` text.

Example log line:

```
2025-09-27T12:34:56+0000 INFO google_search_mcp: search q_hash=1a2b3c4d dt_ms=123 num=5 start=1 safe=off endpoint=cse q="site:python.org httpx"
```

When a client spawns the server via `uvx`, logs go to the server process’s stderr by default (safe for MCP stdio). To persist logs regardless of the client’s stderr handling:

- Set a file path (absolute recommended):
   ```
   GOOGLE_LOG_QUERIES=true
   GOOGLE_LOG_FILE=/var/log/google_search_mcp.log
   ```
- Or redirect stderr in the launch command:
   ```
   uvx --from /path/to/repo google-search-mcp 2>> /tmp/google_search_mcp.log
   ```

## Testing

### Unit Tests

Run the test suite to validate functionality:

```bash
# Run all tests
uv run pytest

# Run with quiet output
uv run pytest -q

# Run specific test files
uv run pytest tests/test_server.py
uv run pytest tests/test_server_http.py
```

## Testing

## Testing

The project includes a comprehensive test suite located in the `tests/` directory. All tests use pytest and mock external dependencies for reliable, fast execution.

### Unit Tests

Run the comprehensive test suite to validate functionality:

```bash
# Run all tests
uv run pytest

# Run with quiet output
uv run pytest -q

# Run specific test modules
uv run pytest tests/test_server.py              # Core MCP server functionality  
uv run pytest tests/test_server_http.py         # HTTP endpoint testing
uv run pytest tests/test_server_http_stream.py  # HTTP streaming testing
uv run pytest tests/test_client.py              # Client integration
uv run pytest tests/test_logging.py             # Logging configuration
```

### Local Testing

Use an MCP client (e.g., Inspector or your app) that supports SSE or Streamable HTTP transports. There is no custom REST `list_tools`/`call_tool` in this server.

### AWS Gateway Testing

For AWS AgentCore Gateway deployments, use the dedicated test script:

```bash
# Test gateway with authentication
python3 deploy_aws_agentcore_auth0/test_gateway_auth0.py \
   "https://your-gateway.amazonaws.com/mcp" \
   "client-id" \
   "client-secret" \
   "https://your-domain.auth0.com" \
   "https://your-gateway.amazonaws.com/mcp"  # audience (optional depending on IdP)
```

This validates authentication, tool listing, and tool execution through the gateway.

## Deployment Details

### AWS Lambda + AgentCore Gateway
- Uses JSON-RPC 2.0 protocol with OAuth authentication
- Cognito client credentials flow required
- Manual console configuration for compute targets and MCP providers (APIs not publicly available)
- See [`deploy/README-lambda-zip.md`](deploy/README-lambda-zip.md) for detailed instructions (use scripts under `deploy_aws_agentcore_auth0/`)

### AWS AgentCore Runtime  
- Uses preview AgentCore SDK (placeholder implementation)
- Requires manual configuration as APIs are not publicly available
- Container-based deployment via ECR integration
- Provides persistent sessions with microVM isolation

TDQS

A3.7/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no possibility of confusion or overlap between tools. The single 'search' tool has a clearly defined and distinct purpose that cannot be mistaken for any other tool in this server.

Naming Consistency5/5

The naming is trivially consistent as there is only one tool named 'search'. This follows a simple verb pattern and there are no other tools to create inconsistency or mixed conventions.

Tool Count2/5

A single tool is too few for a server named 'Google Search MCP Server', which suggests broader search functionality. While the tool is feature-rich, the server lacks complementary tools like image_search, news_search, or advanced filtering tools that would make the set more complete and appropriate for the domain.

Completeness2/5

The server is severely incomplete for a Google Search domain. It only provides a general web search tool, missing obvious gaps such as image search, video search, news search, or specialized search types that agents would expect from a comprehensive search interface. This will likely cause agent failures when trying to perform common search-related tasks beyond basic web queries.

Maintenance

ActivityInactive
ResponsivenessNo issues