Metadata-Version: 2.4
Name: mcp-google-oauth
Version: 0.1.0
Summary: Drop-in Google OAuth 2.0 authentication for MCP servers
License-Expression: MIT
Project-URL: Homepage, https://github.com/hungvietdo/mcp-google-oauth
Project-URL: Repository, https://github.com/hungvietdo/mcp-google-oauth
Project-URL: Issues, https://github.com/hungvietdo/mcp-google-oauth/issues
Keywords: mcp,oauth,google,authentication,llm,claude
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: fastapi>=0.115.0
Requires-Dist: httpx>=0.27.0
Requires-Dist: itsdangerous>=2.0.0
Requires-Dist: sqlalchemy>=2.0.0
Requires-Dist: mcp[cli]>=1.6.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: uvicorn[standard]>=0.30.0
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Dynamic: license-file

# MCP Server with Google OAuth 2.0 Authentication

Building an MCP server is straightforward — but adding proper authentication is not. The [MCP spec](https://modelcontextprotocol.io/) requires OAuth 2.0 with discovery endpoints, dynamic client registration, PKCE, and token lifecycle management. That's a lot of boilerplate before you can write your first tool.

This project gives you all of that out of the box. You focus on your tools, authentication is handled.

```bash
pip install mcp-google-oauth
```

> **Prerequisite:** This implementation uses Google OAuth 2.0 and is designed for organizations with [Google Workspace](https://workspace.google.com/). Your company domain (e.g. `yourcompany.com`) must be managed by Google Workspace to restrict access to internal users. Other identity providers (Microsoft Entra ID, Okta, etc.) can be implemented following the same OAuth 2.0 methodology used here.

### Why use this

**For developers building MCP servers:**
- Authentication is the hardest part of MCP integration — this eliminates it entirely
- One function call (`create_mcp_app()`) sets up the full OAuth 2.0 stack
- You only write `@mcp.tool()` functions — everything else is provided
- Works with Claude Desktop, Claude.ai, and any MCP-compatible client

**For end users connecting to your MCP server:**
- Sign in with Google — no API tokens, no secrets, no config files to manage
- Browser opens automatically on first use, then stays authenticated for 30 days
- Access is controlled by Google Workspace domain (e.g. only `@yourcompany.com`)

### What's included

- Google OAuth 2.0 sign-in with optional domain restriction
- Token management (1hr access tokens, 30-day refresh, auto-renewal)
- Full MCP protocol compliance (OAuth discovery, client registration, PKCE)
- Health check at `/health`

### A complete MCP server in 15 lines

```python
# main.py
from dotenv import load_dotenv
load_dotenv()
from mcp_auth import create_mcp_app, MCPAuthConfig

config = MCPAuthConfig.from_env()
config.mcp_name = "my-connector"

app, mcp = create_mcp_app(config)

@mcp.tool()
def hello(name: str = "world") -> str:
    """Say hello."""
    return f"Hello, {name}!"
```

---

## How It Works

```mermaid
graph LR
    subgraph Claude
        C[Claude Desktop<br/>or claude.ai]
        MR[mcp-remote]
        C <--> MR
    end

    subgraph Server ["Your Server"]
        AUTH[mcp_auth/<br/>OAuth + token mgmt]
        TOOLS["main.py<br/>@mcp.tool()"]
        DB[(Database<br/>OAuth tokens only)]
        AUTH <--> DB
    end

    subgraph Auth ["Authentication Provider"]
        G[Google OAuth 2.0]
    end

    MR <-->|HTTPS| AUTH
    MR <-->|tool calls| TOOLS
    AUTH <-->|verify identity| G
```

### Auth Flow

```mermaid
sequenceDiagram
    participant C as Claude
    participant S as Your Server
    participant G as Google

    C->>S: POST /mcp/
    S-->>C: 401 Unauthorized

    C->>S: Discover OAuth endpoints
    S-->>C: OAuth metadata

    C->>S: Register client
    S-->>C: client_id + secret

    C->>S: Authorize
    S-->>C: Redirect to Google
    C->>G: User signs in

    G-->>S: Callback + code
    Note over S: Validate domain

    S-->>C: Auth code
    C->>S: Exchange code
    S-->>C: Access + refresh tokens

    C->>S: POST /mcp/ + Bearer token
    S-->>C: Tool result
```

- Access tokens expire in **1 hour** (auto-refreshed by Claude)
- Refresh tokens last **30 days**
- Domain restriction enforced at `/google/callback`
- PKCE (S256) and HMAC-signed state prevent CSRF

See `docs/architecture.md` for detailed diagrams.

---

## Quick Start

### 1. Install

```bash
pip install mcp-google-oauth
```

> **Requires Python 3.11+.** Check with `python3 --version`. If needed: `brew install python@3.13` (macOS) or see [python.org](https://www.python.org/downloads/).

Alternatively, clone and install from source:

```bash
git clone https://github.com/hungvietdo/mcp-google-oauth.git
cd mcp-google-oauth
python3 -m venv .venv && source .venv/bin/activate
pip install -e .
```

### 2. Set up Google OAuth credentials

1. Go to [Google Cloud Console](https://console.cloud.google.com)
2. **APIs & Services → OAuth consent screen**
   - User Type: **Internal** (restricts to your Google Workspace org)
   - Fill in app name + contact email → Save
3. **APIs & Services → Credentials → Create Credentials → OAuth 2.0 Client ID**
   - Application type: **Web application**
   - Authorized redirect URI: `https://YOUR_DOMAIN/google/callback`
4. Copy **Client ID** and **Client Secret**

### 3. Configure environment

```bash
cp .env.example .env
```

Edit `.env`:

```env
SESSION_SECRET=<run: python -c "import secrets; print(secrets.token_hex(32))">
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret
ALLOWED_DOMAIN=yourcompany.com
DATABASE_URL=sqlite:///./local.db
MCP_ISSUER_URL=https://your-domain.ngrok.app/mcp
GOOGLE_MCP_CALLBACK_URL=https://your-domain.ngrok.app/google/callback
```

### 4. Run

```bash
mcp-google-oauth
```

Or with options:

```bash
mcp-google-oauth --port 9000 --reload   # dev mode, custom port
```

Or via uvicorn directly:

```bash
uvicorn main:app --port 8080
```

> **Exposing to the internet:** If you need to make your local MCP server publicly accessible (e.g. for Claude.ai or testing from another machine), you can use [ngrok](https://ngrok.com/):
> ```bash
> ngrok http 8080 --domain=your-domain.ngrok.app
> ```
> Update `MCP_ISSUER_URL` and `GOOGLE_MCP_CALLBACK_URL` in your `.env` to match the ngrok URL.

### 5. Connect from Claude

**Claude.ai** (Pro/Max/Team/Enterprise) — go to **Customize → Connectors → Add custom connector** and paste your MCP server URL. Either format works:
- `https://your-domain.ngrok.app/mcp/`
- `https://your-domain.ngrok.app/`

First use opens your browser for Google sign-in. No tokens in config files.

> **Advanced:** You can also connect via Claude Desktop or Claude Code by adding the server to your MCP config. See [Claude MCP docs](https://modelcontextprotocol.io/quickstart/user) for details.

---

## Project Structure

```
├── pyproject.toml           # Package definition — pip install mcp-google-oauth
├── main.py                  # Your MCP server — define tools here
├── .env.example             # Template for credentials
│
├── mcp_auth/                # Installable auth package
│   ├── __init__.py          # create_mcp_app() + MCPAuthConfig
│   ├── cli.py               # mcp-google-oauth CLI entrypoint
│   ├── database.py          # SQLAlchemy engine + session
│   ├── models.py            # OAuth token tables (auto-created)
│   ├── oauth_provider.py    # Google OAuth 2.0 provider
│   ├── middleware.py        # Path rewrite fix for mcp-remote
│   ├── routes.py            # /google/callback, /health
│   └── example_main.py     # Starter template
│
└── docs/
    └── architecture.md      # Detailed diagrams (OAuth flow, data model, security)
```

---

## Configuration

### Environment Variables

| Variable | Required | Description |
|---|---|---|
| `GOOGLE_CLIENT_ID` | Yes | From Google Cloud Console |
| `GOOGLE_CLIENT_SECRET` | Yes | From Google Cloud Console |
| `GOOGLE_MCP_CALLBACK_URL` | Yes | `https://your-domain/google/callback` |
| `MCP_ISSUER_URL` | Yes | `https://your-domain/mcp` |
| `SESSION_SECRET` | Yes | Random hex string for signing sessions |
| `ALLOWED_DOMAIN` | No | Restrict to a Google Workspace domain (e.g. `yourcompany.com`) |
| `DATABASE_URL` | No | Default: `sqlite:///./local.db` |

> **Why a database?** The database only stores OAuth access and refresh tokens. It does not store any application data. Tables are auto-created on startup. If the database is deleted, users simply re-authenticate with Google on their next request — no data is lost.

### MCPAuthConfig Properties

Set in code after `MCPAuthConfig.from_env()`:

| Property | Default | Description |
|---|---|---|
| `mcp_name` | `"mcp-server"` | MCP server name shown in Claude |
| `mcp_instructions` | `""` | Instructions for Claude about available tools |

---

## License

MIT
