Skip to main content

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:
{
  "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

The simplest way to use MCP Identity is with the Agent class:
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:
EnvironmentAuth Method
Local CLIOpens system browser
Jupyter NotebookShows clickable button, opens popup
StreamlitShows link in Streamlit UI
SSH/RemoteDisplays URL for manual opening
Google ColabOpens popup window

Option 2: Low-Level Client (Manual Control)

For custom UIs or more control:
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:
# 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:
# 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:
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

ProviderServicesStatus
GoogleGmail, Calendar, Drive, Docs, SheetsAvailable
GitHubRepos, Issues, PRsComing Soon
NotionPages, DatabasesComing Soon
SlackMessages, ChannelsComing 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