> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mcprank.app/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Identity

> Authenticate users and access their data securely

# MCP Identity

MCP Identity lets your AI agent access user data (Gmail, Calendar, Drive, etc.) without handling OAuth credentials directly. Users connect their accounts once, and MCP Rank stores their tokens securely server-side.

## Key Concepts

### Server-Side Token Storage

Unlike traditional OAuth integrations where you store tokens in your database, MCP Rank handles all token storage:

* **You provide**: A `user_id` (your user's ID in your system)
* **We store**: OAuth tokens encrypted with AWS KMS
* **You receive**: An MCP Identity Token (MIT) for making requests

This means you never see or handle Google OAuth tokens directly.

### MCP Identity Token (MIT)

The MIT is a short-lived JWT (1 hour) that identifies your user:

```json theme={null}
{
  "user_id": "user_123",
  "developer_id": "dev_abc",
  "exp": 1704067200
}
```

Use this token in the `Authorization` header when making proxy requests.

### Just-In-Time (JIT) Authentication

When your agent needs to access user data:

1. Request fails with "provider not connected"
2. SDK automatically opens browser for OAuth
3. User authorizes access
4. Tokens stored server-side
5. Request retries and succeeds

## How It Works

```mermaid theme={null}
sequenceDiagram
    participant Agent as Your Agent
    participant SDK as MCP Rank SDK
    participant API as MCP Rank API
    participant Google

    Agent->>SDK: Initialize with user_id
    SDK->>API: POST /v1/identity/token
    API-->>SDK: MIT (access_token)
    
    Agent->>SDK: proxy_get("google", "gmail/...")
    SDK->>API: Request + MIT
    API-->>SDK: 403 provider_not_connected
    
    SDK->>API: POST /v1/identity/sessions
    API-->>SDK: {session_id, auth_url}
    SDK->>SDK: Open browser to auth_url
    
    Note over SDK,Google: User authorizes in browser
    Google->>API: OAuth callback
    API->>API: Store tokens (KMS encrypted)
    
    SDK->>API: GET /v1/identity/sessions/{id}
    API-->>SDK: {status: "complete"}
    
    SDK->>API: Retry request + MIT
    API->>Google: API call (using stored token)
    Google-->>API: Response
    API-->>SDK: Response
    SDK-->>Agent: Data
```

## Option 1: Agent with Auto-Auth (Recommended)

The simplest way to use MCP Identity is with the `Agent` class:

```python theme={null}
from openai import OpenAI
from mcp_rank import Agent

# Create agent with user_id and auto_auth
agent = Agent(
    OpenAI(),
    api_key="sk_mcp_rank_...",
    user_id="user_123",   # Your user's ID
    auto_auth=True,       # Opens browser when auth needed
)

# Agent handles everything:
# - Tool discovery
# - JIT authentication (browser popup if needed)
# - Token refresh
# - Retry logic
response = agent.run("Check my calendar for tomorrow's meetings")
print(response)
```

### Environment Detection

The SDK automatically detects your environment and handles auth appropriately:

| Environment      | Auth Method                         |
| ---------------- | ----------------------------------- |
| Local CLI        | Opens system browser                |
| Jupyter Notebook | Shows clickable button, opens popup |
| Streamlit        | Shows link in Streamlit UI          |
| SSH/Remote       | Displays URL for manual opening     |
| Google Colab     | Opens popup window                  |

## Option 2: Low-Level Client (Manual Control)

For custom UIs or more control:

```python theme={null}
import asyncio
from mcp_rank import MCPRankClient

async def access_user_gmail(user_id: str):
    client = MCPRankClient(
        api_key="sk_mcp_rank_...",
        user_id=user_id,
    )
    
    # Step 1: Initialize - gets MIT from server
    await client.initialize()
    
    # Step 2: Check if user has connected Google
    try:
        info = await client.get_proxy_info("google")
        can_access = info.get("can_access", False)
    except Exception:
        can_access = False
    
    if not can_access:
        # Step 3: Create auth session
        session = await client.create_auth_session("google")
        
        # Step 4: Display auth URL to user (your UI handles this)
        auth_url = session["auth_url"]
        session_id = session["session_id"]
        
        # In a web app, you might redirect:
        # return RedirectResponse(auth_url)
        
        # In CLI, display the URL:
        print(f"Please authenticate: {auth_url}")
        
        # Step 5: Poll for completion
        while True:
            status = await client.check_session_status(session_id)
            if status["status"] == "complete":
                print("Authentication successful!")
                break
            elif status["status"] == "error":
                raise Exception(f"Auth failed: {status.get('error')}")
            await asyncio.sleep(1)
        
        # Step 6: Refresh client after auth
        client._initialized = False
        await client.initialize()
    
    # Step 7: Access user data
    profile = await client.proxy_get("google", "gmail/v1/users/me/profile")
    return profile

# Run it
profile = asyncio.run(access_user_gmail("user_123"))
print(f"Email: {profile['emailAddress']}")
```

## Token Lifecycle

### Automatic Refresh

The SDK handles token refresh automatically. MITs expire after 1 hour, and OAuth tokens are refreshed server-side when needed.

### Manual Refresh

If needed, you can manually refresh:

```python theme={null}
# Refresh MIT
new_tokens = await client.refresh_user_token()

# Or re-initialize (fetches fresh MIT)
client._initialized = False
await client.initialize()
```

### Revoke Access

Let users disconnect their accounts:

```python theme={null}
# Revoke all tokens for this user
await client.revoke_user_token()

# Clear local state
client.clear_user_token()
```

Users can also revoke access from the MCP Rank dashboard or their Google account settings.

## Handling AuthRequiredError

When using the low-level client without `auto_auth`, you'll receive an `AuthRequiredError` when authentication is needed:

```python theme={null}
from mcp_rank import MCPRankClient
from mcp_rank.auth import AuthRequiredError

async def safe_proxy_call(client, provider, path):
    try:
        return await client.proxy_get(provider, path)
    except AuthRequiredError as e:
        # e.provider - which provider needs auth (e.g., "google")
        # e.auth_url - URL to redirect user to
        print(f"Auth needed for {e.provider}")
        print(f"Please visit: {e.auth_url}")
        raise
```

## Supported Providers

| Provider | Services                             | Status      |
| -------- | ------------------------------------ | ----------- |
| Google   | Gmail, Calendar, Drive, Docs, Sheets | Available   |
| GitHub   | Repos, Issues, PRs                   | Coming Soon |
| Notion   | Pages, Databases                     | Coming Soon |
| Slack    | Messages, Channels                   | Coming Soon |

## Security

* **KMS Encryption**: OAuth tokens encrypted at rest using AWS KMS (HSM-backed)
* **Short-Lived MITs**: Identity tokens expire in 1 hour
* **Automatic Refresh**: OAuth tokens refreshed server-side, rotated regularly
* **User Control**: Users can revoke access anytime from dashboard or provider settings
* **No Token Exposure**: Your application never sees raw OAuth tokens
