diff --git a/README.md b/README.md
index 1f2fb07..1132685 100644
--- a/README.md
+++ b/README.md
@@ -53,7 +53,7 @@ A production-ready MCP server that integrates all major Google Workspace service
 
 ## Features
 
-- **🔐 Advanced OAuth 2.0**: Secure authentication with automatic token refresh, transport-aware callback handling, session management, and centralized scope management
+- **🔐 Advanced OAuth 2.0 & OAuth 2.1**: Secure authentication with automatic token refresh, transport-aware callback handling, session management, centralized scope management, and OAuth 2.1 bearer token support for multi-user environments with innovative CORS proxy architecture
 - **📅 Google Calendar**: Full calendar management with event CRUD operations
 - **📁 Google Drive**: File operations with native Microsoft Office format support (.docx, .xlsx)
 - **📧 Gmail**: Complete email management with search, send, and draft capabilities
@@ -89,8 +89,8 @@ A production-ready MCP server that integrates all major Google Workspace service
 
 | Variable | Purpose |
 |----------|---------|
-| `GOOGLE_OAUTH_CLIENT_ID` | OAuth client ID from Google Cloud |
-| `GOOGLE_OAUTH_CLIENT_SECRET` | OAuth client secret |
+| `GOOGLE_OAUTH_CLIENT_ID` | OAuth client ID from Google Cloud (used by both legacy auth and OAuth 2.1) |
+| `GOOGLE_OAUTH_CLIENT_SECRET` | OAuth client secret (used by both legacy auth and OAuth 2.1) |
 | `USER_GOOGLE_EMAIL` *(optional)* | Default email for single-user auth |
 | `GOOGLE_PSE_API_KEY` *(optional)* | API key for Google Custom Search - see [Custom Search Setup](#google-custom-search-setup) |
 | `GOOGLE_PSE_ENGINE_ID` *(optional)* | Programmable Search Engine ID for Custom Search |
@@ -228,6 +228,42 @@ docker run -p 8000:8000 -v $(pwd):/app workspace-mcp --transport streamable-http
 
 **Available Tools for `--tools` flag**: `gmail`, `drive`, `calendar`, `docs`, `sheets`, `forms`, `tasks`, `chat`, `search`
 
+### OAuth 2.1 Support (Multi-User Bearer Token Authentication)
+
+The server includes OAuth 2.1 support for bearer token authentication, enabling multi-user session management. **OAuth 2.1 automatically reuses your existing `GOOGLE_OAUTH_CLIENT_ID` and `GOOGLE_OAUTH_CLIENT_SECRET` credentials** - no additional configuration needed!
+
+**When to use OAuth 2.1:**
+- Multiple users accessing the same MCP server instance
+- Need for bearer token authentication instead of passing user emails
+- Building web applications or APIs on top of the MCP server
+- Production environments requiring secure session management
+- Browser-based clients requiring CORS support
+
+**Enabling OAuth 2.1:**
+```bash
+# OAuth 2.1 requires HTTP transport mode
+uv run main.py --transport streamable-http
+
+# The server will automatically detect your GOOGLE_OAUTH_CLIENT_ID/SECRET
+# and initialize OAuth 2.1 if available
+```
+
+**Innovative CORS Proxy Architecture:**
+
+This implementation solves two critical challenges when using Google OAuth in browser environments:
+
+1. **Dynamic Client Registration**: Google doesn't support OAuth 2.1 dynamic client registration. Our server provides a clever proxy that accepts any client registration request and returns the pre-configured Google OAuth credentials, allowing standards-compliant clients to work seamlessly.
+
+2. **CORS Issues**: Google's OAuth endpoints don't include CORS headers, blocking browser-based clients. We implement intelligent proxy endpoints that:
+   - Proxy authorization server discovery requests through `/auth/discovery/authorization-server/{server}`
+   - Proxy token exchange requests through `/oauth2/token` 
+   - Add proper CORS headers to all responses
+   - Maintain security by only proxying to known Google OAuth endpoints
+
+This architecture enables any OAuth 2.1 compliant client to authenticate users through Google, even from browser environments, without requiring changes to the client implementation.
+
+For detailed OAuth 2.1 setup and client implementation, see [docs/oauth21-setup.md](docs/oauth21-setup.md).
+
 ### Connect to Claude Desktop
 
 The server supports two transport modes:
diff --git a/auth/fastmcp_google_auth.py b/auth/fastmcp_google_auth.py
new file mode 100644
index 0000000..627c5eb
--- /dev/null
+++ b/auth/fastmcp_google_auth.py
@@ -0,0 +1,444 @@
+"""
+Google Workspace Authentication Provider for FastMCP
+
+This module implements OAuth 2.1 authentication for Google Workspace using FastMCP's
+built-in authentication patterns. It acts as a Resource Server (RS) that trusts
+Google as the Authorization Server (AS).
+
+Key features:
+- JWT token verification using Google's public keys
+- Discovery metadata endpoints for MCP protocol compliance
+- CORS proxy endpoints to work around Google's CORS limitations
+- Session bridging to Google credentials for API access
+"""
+
+import os
+import logging
+from typing import Dict, Any, Optional, List
+from urllib.parse import urlencode
+
+import aiohttp
+from starlette.responses import JSONResponse
+from starlette.routing import Route
+from starlette.requests import Request
+
+from fastmcp.server.auth.auth import AuthProvider
+from fastmcp.server.auth.providers.jwt import JWTVerifier
+from mcp.server.auth.provider import AccessToken
+
+logger = logging.getLogger(__name__)
+
+
+class GoogleWorkspaceAuthProvider(AuthProvider):
+    """
+    Authentication provider for Google Workspace integration.
+    
+    This provider implements the Remote Authentication pattern where:
+    - Google acts as the Authorization Server (AS)
+    - This MCP server acts as a Resource Server (RS)
+    - Tokens are verified using Google's public keys
+    """
+    
+    def __init__(self):
+        """Initialize the Google Workspace auth provider."""
+        super().__init__()
+        
+        # Get configuration from environment
+        self.client_id = os.getenv("GOOGLE_OAUTH_CLIENT_ID")
+        self.client_secret = os.getenv("GOOGLE_OAUTH_CLIENT_SECRET")
+        self.base_url = os.getenv("WORKSPACE_MCP_BASE_URI", "http://localhost")
+        self.port = int(os.getenv("PORT", os.getenv("WORKSPACE_MCP_PORT", 8000)))
+        
+        if not self.client_id:
+            logger.warning("GOOGLE_OAUTH_CLIENT_ID not set - OAuth 2.1 authentication will not work")
+            return
+            
+        # Initialize JWT verifier for Google tokens
+        self.jwt_verifier = JWTVerifier(
+            jwks_uri="https://www.googleapis.com/oauth2/v3/certs",
+            issuer="https://accounts.google.com",
+            audience=self.client_id,
+            algorithm="RS256"
+        )
+        
+        # Session store for bridging to Google credentials
+        self._sessions: Dict[str, Dict[str, Any]] = {}
+        
+    async def verify_token(self, token: str) -> Optional[AccessToken]:
+        """
+        Verify a bearer token issued by Google.
+        
+        Args:
+            token: The bearer token to verify
+            
+        Returns:
+            AccessToken object if valid, None otherwise
+        """
+        if not self.client_id:
+            return None
+            
+        try:
+            # Use FastMCP's JWT verifier
+            access_token = await self.jwt_verifier.verify_token(token)
+            
+            if access_token:
+                # Store session info for credential bridging
+                session_id = f"google_{access_token.claims.get('sub', 'unknown')}"
+                self._sessions[session_id] = {
+                    "access_token": token,
+                    "user_email": access_token.claims.get("email"),
+                    "claims": access_token.claims,
+                    "scopes": access_token.scopes or []
+                }
+                
+                logger.debug(f"Successfully verified Google token for user: {access_token.claims.get('email')}")
+                
+            return access_token
+            
+        except Exception as e:
+            logger.error(f"Failed to verify Google token: {e}")
+            return None
+    
+    def customize_auth_routes(self, routes: List[Route]) -> List[Route]:
+        """
+        Add custom routes for OAuth discovery and CORS proxy.
+        
+        This implements:
+        1. Protected resource metadata endpoint (RFC9728)
+        2. Authorization server discovery proxy (to avoid CORS)
+        3. Token exchange proxy (to avoid CORS)
+        4. Client configuration endpoint
+        """
+        
+        # Protected Resource Metadata endpoint
+        async def protected_resource_metadata(request: Request):
+            """Return metadata about this protected resource."""
+            metadata = {
+                "resource": f"{self.base_url}:{self.port}",
+                "authorization_servers": [
+                    # Point to the standard well-known endpoint
+                    f"{self.base_url}:{self.port}"
+                ],
+                "bearer_methods_supported": ["header"],
+                "scopes_supported": [
+                    "https://www.googleapis.com/auth/userinfo.email",
+                    "https://www.googleapis.com/auth/userinfo.profile",
+                    "https://www.googleapis.com/auth/calendar",
+                    "https://www.googleapis.com/auth/drive",
+                    "https://www.googleapis.com/auth/gmail.modify",
+                    "https://www.googleapis.com/auth/documents",
+                    "https://www.googleapis.com/auth/spreadsheets",
+                    "https://www.googleapis.com/auth/presentations",
+                    "https://www.googleapis.com/auth/chat.spaces",
+                    "https://www.googleapis.com/auth/forms",
+                    "https://www.googleapis.com/auth/tasks"
+                ],
+                "resource_documentation": "https://developers.google.com/workspace",
+                "client_registration_required": True,
+                "client_configuration_endpoint": f"{self.base_url}:{self.port}/.well-known/oauth-client"
+            }
+            
+            return JSONResponse(
+                content=metadata,
+                headers={"Content-Type": "application/json"}
+            )
+        
+        routes.append(Route("/.well-known/oauth-protected-resource", protected_resource_metadata))
+        
+        # OAuth authorization server metadata endpoint
+        async def authorization_server_metadata(request: Request):
+            """Forward authorization server metadata from Google."""
+            try:
+                async with aiohttp.ClientSession() as session:
+                    # Try OpenID configuration first
+                    url = "https://accounts.google.com/.well-known/openid-configuration"
+                    async with session.get(url) as response:
+                        if response.status == 200:
+                            metadata = await response.json()
+                            
+                            # Add OAuth 2.1 required fields
+                            metadata.setdefault("code_challenge_methods_supported", ["S256"])
+                            metadata.setdefault("pkce_required", True)
+                            
+                            # Override token endpoint to use our proxy
+                            metadata["token_endpoint"] = f"{self.base_url}:{self.port}/oauth2/token"
+                            metadata["authorization_endpoint"] = f"{self.base_url}:{self.port}/oauth2/authorize"
+                            
+                            return JSONResponse(
+                                content=metadata,
+                                headers={
+                                    "Content-Type": "application/json",
+                                    "Access-Control-Allow-Origin": "*",
+                                    "Access-Control-Allow-Methods": "GET, OPTIONS",
+                                    "Access-Control-Allow-Headers": "Content-Type, Authorization"
+                                }
+                            )
+                
+                # Fallback to default Google OAuth metadata
+                return JSONResponse(
+                    content={
+                        "issuer": "https://accounts.google.com",
+                        "authorization_endpoint": f"{self.base_url}:{self.port}/oauth2/authorize",
+                        "token_endpoint": f"{self.base_url}:{self.port}/oauth2/token",
+                        "userinfo_endpoint": "https://www.googleapis.com/oauth2/v2/userinfo",
+                        "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
+                        "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
+                        "response_types_supported": ["code"],
+                        "code_challenge_methods_supported": ["S256"],
+                        "pkce_required": True,
+                        "grant_types_supported": ["authorization_code", "refresh_token"],
+                        "scopes_supported": ["openid", "email", "profile"],
+                        "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"]
+                    },
+                    headers={
+                        "Content-Type": "application/json",
+                        "Access-Control-Allow-Origin": "*"
+                    }
+                )
+                
+            except Exception as e:
+                logger.error(f"Error fetching auth server metadata: {e}")
+                return JSONResponse(
+                    status_code=500,
+                    content={"error": "Failed to fetch authorization server metadata"}
+                )
+        
+        routes.append(Route("/.well-known/oauth-authorization-server", authorization_server_metadata))
+        
+        # Authorization server discovery proxy
+        async def proxy_auth_server_discovery(request: Request):
+            """Proxy authorization server metadata to avoid CORS issues."""
+            server_host = request.path_params.get("server_host", "accounts.google.com")
+            
+            # Only allow known Google OAuth endpoints
+            allowed_hosts = ["accounts.google.com", "oauth2.googleapis.com"]
+            if server_host not in allowed_hosts:
+                return JSONResponse(
+                    status_code=400,
+                    content={"error": "Invalid authorization server"}
+                )
+            
+            try:
+                # Fetch metadata from Google
+                async with aiohttp.ClientSession() as session:
+                    # Try OpenID configuration first
+                    url = f"https://{server_host}/.well-known/openid-configuration"
+                    async with session.get(url) as response:
+                        if response.status == 200:
+                            metadata = await response.json()
+                            
+                            # Add OAuth 2.1 required fields
+                            metadata.setdefault("code_challenge_methods_supported", ["S256"])
+                            metadata.setdefault("pkce_required", True)
+                            
+                            return JSONResponse(
+                                content=metadata,
+                                headers={
+                                    "Content-Type": "application/json",
+                                    "Access-Control-Allow-Origin": "*",
+                                    "Access-Control-Allow-Methods": "GET, OPTIONS",
+                                    "Access-Control-Allow-Headers": "Content-Type, Authorization"
+                                }
+                            )
+                
+                # Fallback to default Google OAuth metadata
+                return JSONResponse(
+                    content={
+                        "issuer": f"https://{server_host}",
+                        "authorization_endpoint": f"https://{server_host}/o/oauth2/v2/auth",
+                        "token_endpoint": f"https://{server_host}/token",
+                        "userinfo_endpoint": "https://www.googleapis.com/oauth2/v2/userinfo",
+                        "revocation_endpoint": f"https://{server_host}/revoke",
+                        "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
+                        "response_types_supported": ["code"],
+                        "code_challenge_methods_supported": ["S256"],
+                        "pkce_required": True,
+                        "grant_types_supported": ["authorization_code", "refresh_token"],
+                        "scopes_supported": ["openid", "email", "profile"],
+                        "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"]
+                    },
+                    headers={
+                        "Content-Type": "application/json",
+                        "Access-Control-Allow-Origin": "*"
+                    }
+                )
+                
+            except Exception as e:
+                logger.error(f"Error proxying auth server discovery: {e}")
+                return JSONResponse(
+                    status_code=500,
+                    content={"error": "Failed to fetch authorization server metadata"}
+                )
+        
+        routes.append(Route("/auth/discovery/authorization-server/{server_host:path}", proxy_auth_server_discovery))
+        
+        # Token exchange proxy endpoint
+        async def proxy_token_exchange(request: Request):
+            """Proxy token exchange to Google to avoid CORS issues."""
+            if request.method == "OPTIONS":
+                return JSONResponse(
+                    content={},
+                    headers={
+                        "Access-Control-Allow-Origin": "*",
+                        "Access-Control-Allow-Methods": "POST, OPTIONS",
+                        "Access-Control-Allow-Headers": "Content-Type, Authorization"
+                    }
+                )
+            
+            try:
+                # Get form data
+                body = await request.body()
+                content_type = request.headers.get("content-type", "application/x-www-form-urlencoded")
+                
+                # Determine which Google token endpoint to use
+                token_endpoint = "https://oauth2.googleapis.com/token"
+                
+                # Forward request to Google
+                async with aiohttp.ClientSession() as session:
+                    headers = {"Content-Type": content_type}
+                    
+                    async with session.post(token_endpoint, data=body, headers=headers) as response:
+                        response_data = await response.json()
+                        
+                        # Log for debugging
+                        if response.status != 200:
+                            logger.error(f"Token exchange failed: {response.status} - {response_data}")
+                        else:
+                            logger.info("Token exchange successful")
+                            
+                            # Store session for credential bridging
+                            if "access_token" in response_data:
+                                # Try to decode the token to get user info
+                                try:
+                                    access_token = await self.verify_token(response_data["access_token"])
+                                    if access_token:
+                                        session_id = f"google_{access_token.claims.get('sub', 'unknown')}"
+                                        self._sessions[session_id] = {
+                                            "token_response": response_data,
+                                            "user_email": access_token.claims.get("email"),
+                                            "claims": access_token.claims
+                                        }
+                                except Exception as e:
+                                    logger.debug(f"Could not verify token for session storage: {e}")
+                        
+                        return JSONResponse(
+                            status_code=response.status,
+                            content=response_data,
+                            headers={
+                                "Content-Type": "application/json",
+                                "Access-Control-Allow-Origin": "*",
+                                "Cache-Control": "no-store"
+                            }
+                        )
+                        
+            except Exception as e:
+                logger.error(f"Error in token proxy: {e}")
+                return JSONResponse(
+                    status_code=500,
+                    content={"error": "server_error", "error_description": str(e)},
+                    headers={"Access-Control-Allow-Origin": "*"}
+                )
+        
+        routes.append(Route("/oauth2/token", proxy_token_exchange, methods=["POST", "OPTIONS"]))
+        
+        # OAuth client configuration endpoint
+        async def oauth_client_config(request: Request):
+            """Return OAuth client configuration for dynamic registration workaround."""
+            if not self.client_id:
+                return JSONResponse(
+                    status_code=404,
+                    content={"error": "OAuth not configured"}
+                )
+            
+            return JSONResponse(
+                content={
+                    "client_id": self.client_id,
+                    "client_name": "Google Workspace MCP Server",
+                    "client_uri": f"{self.base_url}:{self.port}",
+                    "redirect_uris": [
+                        f"{self.base_url}:{self.port}/oauth2callback",
+                        "http://localhost:5173/auth/callback"  # Common dev callback
+                    ],
+                    "grant_types": ["authorization_code", "refresh_token"],
+                    "response_types": ["code"],
+                    "scope": "openid email profile https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/gmail.modify",
+                    "token_endpoint_auth_method": "client_secret_basic",
+                    "code_challenge_methods": ["S256"]
+                },
+                headers={
+                    "Content-Type": "application/json",
+                    "Access-Control-Allow-Origin": "*"
+                }
+            )
+        
+        routes.append(Route("/.well-known/oauth-client", oauth_client_config))
+        
+        # OAuth authorization endpoint (redirect to Google)
+        async def oauth_authorize(request: Request):
+            """Redirect to Google's authorization endpoint."""
+            if request.method == "OPTIONS":
+                return JSONResponse(
+                    content={},
+                    headers={
+                        "Access-Control-Allow-Origin": "*",
+                        "Access-Control-Allow-Methods": "GET, OPTIONS",
+                        "Access-Control-Allow-Headers": "Content-Type"
+                    }
+                )
+            
+            # Get query parameters
+            params = dict(request.query_params)
+            
+            # Add our client ID if not provided
+            if "client_id" not in params and self.client_id:
+                params["client_id"] = self.client_id
+            
+            # Ensure response_type is code
+            params["response_type"] = "code"
+            
+            # Build Google authorization URL
+            google_auth_url = "https://accounts.google.com/o/oauth2/v2/auth?" + urlencode(params)
+            
+            # Return redirect
+            return JSONResponse(
+                status_code=302,
+                headers={
+                    "Location": google_auth_url,
+                    "Access-Control-Allow-Origin": "*"
+                }
+            )
+        
+        routes.append(Route("/oauth2/authorize", oauth_authorize, methods=["GET", "OPTIONS"]))
+        
+        return routes
+    
+    def get_session_info(self, session_id: str) -> Optional[Dict[str, Any]]:
+        """
+        Get session information for credential bridging.
+        
+        Args:
+            session_id: The session identifier
+            
+        Returns:
+            Session information if found
+        """
+        return self._sessions.get(session_id)
+    
+    def create_session_from_token(self, token: str, user_email: str) -> str:
+        """
+        Create a session from an access token for credential bridging.
+        
+        Args:
+            token: The access token
+            user_email: The user's email address
+            
+        Returns:
+            Session ID
+        """
+        session_id = f"google_{user_email}"
+        self._sessions[session_id] = {
+            "access_token": token,
+            "user_email": user_email,
+            "created_at": "now"  # You could use datetime here
+        }
+        return session_id
\ No newline at end of file
diff --git a/auth/google_auth.py b/auth/google_auth.py
index c278ceb..16b5097 100644
--- a/auth/google_auth.py
+++ b/auth/google_auth.py
@@ -16,6 +16,20 @@ from google.auth.exceptions import RefreshError
 from googleapiclient.discovery import build
 from googleapiclient.errors import HttpError
 from auth.scopes import SCOPES
+from auth.oauth21_session_store import get_oauth21_session_store
+from core.config import (
+    WORKSPACE_MCP_PORT,
+    WORKSPACE_MCP_BASE_URI,
+    get_transport_mode,
+    get_oauth_redirect_uri,
+)
+from core.context import get_fastmcp_session_id
+
+# Try to import FastMCP dependencies (may not be available in all environments)
+try:
+    from fastmcp.server.dependencies import get_context as get_fastmcp_context
+except ImportError:
+    get_fastmcp_context = None
 
 # Configure logging
 logging.basicConfig(level=logging.INFO)
@@ -164,6 +178,9 @@ def load_credentials_from_file(
         if creds_data.get("expiry"):
             try:
                 expiry = datetime.fromisoformat(creds_data["expiry"])
+                # Ensure timezone-naive datetime for Google auth library compatibility
+                if expiry.tzinfo is not None:
+                    expiry = expiry.replace(tzinfo=None)
             except (ValueError, TypeError) as e:
                 logger.warning(
                     f"Could not parse expiry time for {user_google_email}: {e}"
@@ -379,15 +396,7 @@ async def start_auth_flow(
         f"[start_auth_flow] Initiating auth for {user_display_name} with global SCOPES."
     )
 
-    # Import here to avoid circular imports
-    from auth.oauth_callback_server import ensure_oauth_callback_available
-    from core.server import _current_transport_mode, WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI
-
-    # Ensure OAuth callback server is available before generating URLs
-    success, error_msg = ensure_oauth_callback_available(_current_transport_mode, WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI)
-    if not success:
-        error_detail = f" ({error_msg})" if error_msg else ""
-        raise Exception(f"Cannot initiate OAuth flow - callback server unavailable{error_detail}. Please ensure the OAuth callback server can start before attempting authentication.")
+    # Note: Caller should ensure OAuth callback is available before calling this function
 
     try:
         if "OAUTHLIB_INSECURE_TRANSPORT" not in os.environ and (
@@ -537,7 +546,7 @@ def get_credentials(
     session_id: Optional[str] = None,
 ) -> Optional[Credentials]:
     """
-    Retrieves stored credentials, prioritizing session, then file. Refreshes if necessary.
+    Retrieves stored credentials, prioritizing OAuth 2.1 store, then session, then file. Refreshes if necessary.
     If credentials are loaded from file and a session_id is present, they are cached in the session.
     In single-user mode, bypasses session mapping and uses any available credentials.
 
@@ -551,6 +560,51 @@ def get_credentials(
     Returns:
         Valid Credentials object or None.
     """
+    # First, try OAuth 2.1 session store if we have a session_id (FastMCP session)
+    if session_id:
+        try:
+            store = get_oauth21_session_store()
+
+            # Try to get credentials by MCP session
+            credentials = store.get_credentials_by_mcp_session(session_id)
+            if credentials:
+                logger.info(f"[get_credentials] Found OAuth 2.1 credentials for MCP session {session_id}")
+
+                # Check scopes
+                if not all(scope in credentials.scopes for scope in required_scopes):
+                    logger.warning(
+                        f"[get_credentials] OAuth 2.1 credentials lack required scopes. Need: {required_scopes}, Have: {credentials.scopes}"
+                    )
+                    return None
+
+                # Return if valid
+                if credentials.valid:
+                    return credentials
+                elif credentials.expired and credentials.refresh_token:
+                    # Try to refresh
+                    try:
+                        credentials.refresh(Request())
+                        logger.info(f"[get_credentials] Refreshed OAuth 2.1 credentials for session {session_id}")
+                        # Update stored credentials
+                        user_email = store.get_user_by_mcp_session(session_id)
+                        if user_email:
+                            store.store_session(
+                                user_email=user_email,
+                                access_token=credentials.token,
+                                refresh_token=credentials.refresh_token,
+                                scopes=credentials.scopes,
+                                expiry=credentials.expiry,
+                                mcp_session_id=session_id
+                            )
+                        return credentials
+                    except Exception as e:
+                        logger.error(f"[get_credentials] Failed to refresh OAuth 2.1 credentials: {e}")
+                        return None
+        except ImportError:
+            pass  # OAuth 2.1 store not available
+        except Exception as e:
+            logger.debug(f"[get_credentials] Error checking OAuth 2.1 store: {e}")
+
     # Check for single-user mode
     if os.getenv("MCP_SINGLE_USER_MODE") == "1":
         logger.info(
@@ -719,6 +773,7 @@ async def get_authenticated_google_service(
     tool_name: str,  # For logging/debugging
     user_google_email: str,  # Required - no more Optional
     required_scopes: List[str],
+    session_id: Optional[str] = None,  # Session context for logging
 ) -> tuple[Any, str]:
     """
     Centralized Google service authentication for all MCP tools.
@@ -737,8 +792,37 @@ async def get_authenticated_google_service(
     Raises:
         GoogleAuthenticationError: When authentication is required or fails
     """
+
+    # Try to get FastMCP session ID if not provided
+    if not session_id:
+        try:
+            # First try context variable (works in async context)
+            session_id = get_fastmcp_session_id()
+            if session_id:
+                logger.debug(f"[{tool_name}] Got FastMCP session ID from context: {session_id}")
+            else:
+                logger.debug(f"[{tool_name}] Context variable returned None/empty session ID")
+        except Exception as e:
+            logger.debug(f"[{tool_name}] Could not get FastMCP session from context: {e}")
+
+        # Fallback to direct FastMCP context if context variable not set
+        if not session_id and get_fastmcp_context:
+            try:
+                fastmcp_ctx = get_fastmcp_context()
+                if fastmcp_ctx and hasattr(fastmcp_ctx, 'session_id'):
+                    session_id = fastmcp_ctx.session_id
+                    logger.debug(f"[{tool_name}] Got FastMCP session ID directly: {session_id}")
+                else:
+                    logger.debug(f"[{tool_name}] FastMCP context exists but no session_id attribute")
+            except Exception as e:
+                logger.debug(f"[{tool_name}] Could not get FastMCP context directly: {e}")
+
+        # Final fallback: log if we still don't have session_id
+        if not session_id:
+            logger.warning(f"[{tool_name}] Unable to obtain FastMCP session ID from any source")
+
     logger.info(
-        f"[{tool_name}] Attempting to get authenticated {service_name} service. Email: '{user_google_email}'"
+        f"[{tool_name}] Attempting to get authenticated {service_name} service. Email: '{user_google_email}', Session: '{session_id}'"
     )
 
     # Validate email format
@@ -752,7 +836,7 @@ async def get_authenticated_google_service(
         user_google_email=user_google_email,
         required_scopes=required_scopes,
         client_secrets_path=CONFIG_CLIENT_SECRETS_PATH,
-        session_id=None,  # Session ID not available in service layer
+        session_id=session_id,  # Pass through session context
     )
 
     if not credentials or not credentials.valid:
@@ -763,12 +847,13 @@ async def get_authenticated_google_service(
             f"[{tool_name}] Valid email '{user_google_email}' provided, initiating auth flow."
         )
 
-        # Import here to avoid circular import
-        from core.server import get_oauth_redirect_uri_for_current_mode
-
         # Ensure OAuth callback is available
-        redirect_uri = get_oauth_redirect_uri_for_current_mode()
-        # Note: We don't know the transport mode here, but the server should have set it
+        from auth.oauth_callback_server import ensure_oauth_callback_available
+        redirect_uri = get_oauth_redirect_uri()
+        success, error_msg = ensure_oauth_callback_available(get_transport_mode(), WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI)
+        if not success:
+            error_detail = f" ({error_msg})" if error_msg else ""
+            raise GoogleAuthenticationError(f"Cannot initiate OAuth flow - callback server unavailable{error_detail}")
 
         # Generate auth URL and raise exception with it
         auth_response = await start_auth_flow(
diff --git a/auth/mcp_oauth21_bridge.py b/auth/mcp_oauth21_bridge.py
new file mode 100644
index 0000000..b1f67bc
--- /dev/null
+++ b/auth/mcp_oauth21_bridge.py
@@ -0,0 +1,149 @@
+"""
+MCP OAuth 2.1 Bridge
+
+This module bridges MCP transport sessions with OAuth 2.1 authenticated sessions,
+allowing tool functions to access the OAuth 2.1 context.
+"""
+
+import logging
+from typing import Dict, Optional, Any
+from datetime import datetime
+
+from auth.session_context import SessionContext, set_session_context
+# OAuth 2.1 is now handled by FastMCP auth
+
+logger = logging.getLogger(__name__)
+
+
+class MCPOAuth21Bridge:
+    """
+    Bridges MCP transport sessions with OAuth 2.1 sessions.
+    
+    This class maintains a mapping between MCP transport session IDs
+    and OAuth 2.1 authenticated sessions.
+    """
+    
+    def __init__(self):
+        # Map MCP transport session ID to OAuth 2.1 session info
+        self._mcp_to_oauth21_map: Dict[str, Dict[str, Any]] = {}
+        # Map OAuth 2.1 session ID to MCP transport session ID
+        self._oauth21_to_mcp_map: Dict[str, str] = {}
+    
+    def link_sessions(
+        self, 
+        mcp_session_id: str, 
+        oauth21_session_id: str,
+        user_id: Optional[str] = None,
+        auth_context: Optional[Any] = None
+    ):
+        """
+        Link an MCP transport session with an OAuth 2.1 session.
+        
+        Args:
+            mcp_session_id: MCP transport session ID
+            oauth21_session_id: OAuth 2.1 session ID
+            user_id: User identifier
+            auth_context: OAuth 2.1 authentication context
+        """
+        session_info = {
+            "oauth21_session_id": oauth21_session_id,
+            "user_id": user_id,
+            "auth_context": auth_context,
+            "linked_at": datetime.utcnow().isoformat(),
+        }
+        
+        self._mcp_to_oauth21_map[mcp_session_id] = session_info
+        self._oauth21_to_mcp_map[oauth21_session_id] = mcp_session_id
+        
+        logger.info(
+            f"Linked MCP session {mcp_session_id} with OAuth 2.1 session {oauth21_session_id} "
+            f"for user {user_id}"
+        )
+    
+    def get_oauth21_session(self, mcp_session_id: str) -> Optional[Dict[str, Any]]:
+        """
+        Get OAuth 2.1 session info for an MCP transport session.
+        
+        Args:
+            mcp_session_id: MCP transport session ID
+            
+        Returns:
+            OAuth 2.1 session information if linked
+        """
+        return self._mcp_to_oauth21_map.get(mcp_session_id)
+    
+    def get_mcp_session(self, oauth21_session_id: str) -> Optional[str]:
+        """
+        Get MCP transport session ID for an OAuth 2.1 session.
+        
+        Args:
+            oauth21_session_id: OAuth 2.1 session ID
+            
+        Returns:
+            MCP transport session ID if linked
+        """
+        return self._oauth21_to_mcp_map.get(oauth21_session_id)
+    
+    def unlink_mcp_session(self, mcp_session_id: str):
+        """
+        Remove the link for an MCP transport session.
+        
+        Args:
+            mcp_session_id: MCP transport session ID
+        """
+        session_info = self._mcp_to_oauth21_map.pop(mcp_session_id, None)
+        if session_info:
+            oauth21_session_id = session_info.get("oauth21_session_id")
+            if oauth21_session_id:
+                self._oauth21_to_mcp_map.pop(oauth21_session_id, None)
+            logger.info(f"Unlinked MCP session {mcp_session_id}")
+    
+    def set_session_context_for_mcp(self, mcp_session_id: str) -> bool:
+        """
+        Set the session context for the current request based on MCP session.
+        
+        Args:
+            mcp_session_id: MCP transport session ID
+            
+        Returns:
+            True if context was set, False otherwise
+        """
+        session_info = self.get_oauth21_session(mcp_session_id)
+        if not session_info:
+            logger.debug(f"No OAuth 2.1 session linked to MCP session {mcp_session_id}")
+            return False
+        
+        # Create and set session context
+        context = SessionContext(
+            session_id=session_info["oauth21_session_id"],
+            user_id=session_info["user_id"],
+            auth_context=session_info["auth_context"],
+            metadata={
+                "mcp_session_id": mcp_session_id,
+                "linked_at": session_info["linked_at"],
+            }
+        )
+        
+        set_session_context(context)
+        logger.debug(
+            f"Set session context for MCP session {mcp_session_id}: "
+            f"OAuth 2.1 session {context.session_id}, user {context.user_id}"
+        )
+        return True
+    
+    def get_stats(self) -> Dict[str, Any]:
+        """Get bridge statistics."""
+        return {
+            "linked_sessions": len(self._mcp_to_oauth21_map),
+            "mcp_sessions": list(self._mcp_to_oauth21_map.keys()),
+            "oauth21_sessions": list(self._oauth21_to_mcp_map.keys()),
+        }
+
+
+# Global bridge instance
+_bridge = MCPOAuth21Bridge()
+
+
+def get_bridge() -> MCPOAuth21Bridge:
+    """Get the global MCP OAuth 2.1 bridge instance."""
+    return _bridge
\ No newline at end of file
diff --git a/auth/mcp_session_middleware.py b/auth/mcp_session_middleware.py
new file mode 100644
index 0000000..9743f4f
--- /dev/null
+++ b/auth/mcp_session_middleware.py
@@ -0,0 +1,113 @@
+"""
+MCP Session Middleware
+
+This middleware intercepts MCP requests and sets the session context
+for use by tool functions.
+"""
+
+import logging
+from typing import Callable, Any
+
+from starlette.middleware.base import BaseHTTPMiddleware
+from starlette.requests import Request
+
+from auth.session_context import (
+    SessionContext,
+    SessionContextManager,
+    extract_session_from_headers,
+)
+# OAuth 2.1 is now handled by FastMCP auth
+
+logger = logging.getLogger(__name__)
+
+
+class MCPSessionMiddleware(BaseHTTPMiddleware):
+    """
+    Middleware that extracts session information from requests and makes it
+    available to MCP tool functions via context variables.
+    """
+    
+    async def dispatch(self, request: Request, call_next: Callable) -> Any:
+        """Process request and set session context."""
+        
+        logger.debug(f"MCPSessionMiddleware processing request: {request.method} {request.url.path}")
+        
+        # Skip non-MCP paths
+        if not request.url.path.startswith("/mcp"):
+            logger.debug(f"Skipping non-MCP path: {request.url.path}")
+            return await call_next(request)
+        
+        session_context = None
+        
+        try:
+            # Extract session information
+            headers = dict(request.headers)
+            session_id = extract_session_from_headers(headers)
+            
+            # Try to get OAuth 2.1 auth context from FastMCP
+            auth_context = None
+            user_email = None
+            mcp_session_id = None
+            
+            # Check for FastMCP auth context
+            if hasattr(request.state, "auth"):
+                auth_context = request.state.auth
+                # Extract user email from auth claims if available
+                if hasattr(auth_context, 'claims') and auth_context.claims:
+                    user_email = auth_context.claims.get('email')
+            
+            # Check for FastMCP session ID (from streamable HTTP transport)
+            if hasattr(request.state, "session_id"):
+                mcp_session_id = request.state.session_id
+                logger.debug(f"Found FastMCP session ID: {mcp_session_id}")
+            
+            # Also check Authorization header for bearer tokens
+            auth_header = headers.get("authorization")
+            if auth_header and auth_header.lower().startswith("bearer ") and not user_email:
+                try:
+                    import jwt
+                    token = auth_header[7:]  # Remove "Bearer " prefix
+                    # Decode without verification to extract email
+                    claims = jwt.decode(token, options={"verify_signature": False})
+                    user_email = claims.get('email')
+                    if user_email:
+                        logger.debug(f"Extracted user email from JWT: {user_email}")
+                except Exception:
+                    pass
+            
+            # Build session context
+            if session_id or auth_context or user_email or mcp_session_id:
+                # Create session ID hierarchy: explicit session_id > Google user session > FastMCP session
+                effective_session_id = session_id
+                if not effective_session_id and user_email:
+                    effective_session_id = f"google_{user_email}"
+                elif not effective_session_id and mcp_session_id:
+                    effective_session_id = mcp_session_id
+                
+                session_context = SessionContext(
+                    session_id=effective_session_id,
+                    user_id=user_email or (auth_context.user_id if auth_context else None),
+                    auth_context=auth_context,
+                    request=request,
+                    metadata={
+                        "path": request.url.path,
+                        "method": request.method,
+                        "user_email": user_email,
+                        "mcp_session_id": mcp_session_id,
+                    }
+                )
+                
+                logger.debug(
+                    f"MCP request with session: session_id={session_context.session_id}, "
+                    f"user_id={session_context.user_id}, path={request.url.path}"
+                )
+            
+            # Process request with session context
+            with SessionContextManager(session_context):
+                response = await call_next(request)
+                return response
+                
+        except Exception as e:
+            logger.error(f"Error in MCP session middleware: {e}")
+            # Continue without session context
+            return await call_next(request)
\ No newline at end of file
diff --git a/auth/oauth21_google_bridge.py b/auth/oauth21_google_bridge.py
new file mode 100644
index 0000000..33ef519
--- /dev/null
+++ b/auth/oauth21_google_bridge.py
@@ -0,0 +1,159 @@
+"""
+Simplified OAuth 2.1 to Google Credentials Bridge
+
+This module bridges FastMCP authentication to Google OAuth2 credentials
+for use with Google API clients.
+"""
+
+import logging
+from typing import Optional
+from datetime import datetime, timezone, timedelta
+from google.oauth2.credentials import Credentials
+from auth.oauth21_session_store import get_oauth21_session_store
+
+logger = logging.getLogger(__name__)
+
+# Global auth provider instance (set during server initialization)
+_auth_provider = None
+
+
+def set_auth_provider(provider):
+    """Set the global auth provider instance."""
+    global _auth_provider
+    _auth_provider = provider
+    logger.info("OAuth 2.1 auth provider configured for Google credential bridging")
+
+
+def get_auth_provider():
+    """Get the global auth provider instance."""
+    return _auth_provider
+
+
+def get_credentials_from_token(access_token: str, user_email: Optional[str] = None) -> Optional[Credentials]:
+    """
+    Convert a bearer token to Google credentials.
+    
+    Args:
+        access_token: The bearer token
+        user_email: Optional user email for session lookup
+        
+    Returns:
+        Google Credentials object or None
+    """
+    if not _auth_provider:
+        logger.error("Auth provider not configured")
+        return None
+        
+    try:
+        # Check if we have session info for this token
+        session_info = None
+        if user_email:
+            session_id = f"google_{user_email}"
+            session_info = _auth_provider.get_session_info(session_id)
+        
+        # If we have a full token response (from token exchange), use it
+        if session_info and "token_response" in session_info:
+            token_data = session_info["token_response"]
+            
+            # Calculate expiry
+            expiry = None
+            if "expires_in" in token_data:
+                # Google auth library expects timezone-naive datetime
+                expiry = datetime.utcnow() + timedelta(seconds=token_data["expires_in"])
+            
+            credentials = Credentials(
+                token=token_data["access_token"],
+                refresh_token=token_data.get("refresh_token"),
+                token_uri="https://oauth2.googleapis.com/token",
+                client_id=_auth_provider.client_id,
+                client_secret=_auth_provider.client_secret,
+                scopes=token_data.get("scope", "").split() if token_data.get("scope") else None,
+                expiry=expiry
+            )
+            
+            logger.debug(f"Created Google credentials from token response for {user_email}")
+            return credentials
+            
+        # Otherwise, create minimal credentials with just the access token
+        else:
+            # Assume token is valid for 1 hour (typical for Google tokens)
+            # Google auth library expects timezone-naive datetime
+            expiry = datetime.utcnow() + timedelta(hours=1)
+            
+            credentials = Credentials(
+                token=access_token,
+                refresh_token=None,
+                token_uri="https://oauth2.googleapis.com/token",
+                client_id=_auth_provider.client_id,
+                client_secret=_auth_provider.client_secret,
+                scopes=None,  # Will be populated from token claims if available
+                expiry=expiry
+            )
+            
+            logger.debug("Created Google credentials from bearer token")
+            return credentials
+            
+    except Exception as e:
+        logger.error(f"Failed to create Google credentials from token: {e}")
+        return None
+
+
+def store_token_session(token_response: dict, user_email: str, mcp_session_id: Optional[str] = None) -> str:
+    """
+    Store a token response in the session store.
+    
+    Args:
+        token_response: OAuth token response from Google
+        user_email: User's email address
+        mcp_session_id: Optional FastMCP session ID to map to this user
+        
+    Returns:
+        Session ID
+    """
+    if not _auth_provider:
+        logger.error("Auth provider not configured")
+        return ""
+        
+    try:
+        # Try to get FastMCP session ID from context if not provided
+        if not mcp_session_id:
+            try:
+                from core.context import get_fastmcp_session_id
+                mcp_session_id = get_fastmcp_session_id()
+                if mcp_session_id:
+                    logger.debug(f"Got FastMCP session ID from context: {mcp_session_id}")
+            except Exception as e:
+                logger.debug(f"Could not get FastMCP session from context: {e}")
+        
+        session_id = f"google_{user_email}"
+        _auth_provider._sessions[session_id] = {
+            "token_response": token_response,
+            "user_email": user_email,
+            "mcp_session_id": mcp_session_id,
+            "created_at": datetime.now(timezone.utc).isoformat()
+        }
+        
+        # Also store in the global OAuth21 session store for compatibility
+        session_store = get_oauth21_session_store()
+        session_store.store_session(
+            user_email=user_email,
+            access_token=token_response.get("access_token"),
+            refresh_token=token_response.get("refresh_token"),
+            token_uri="https://oauth2.googleapis.com/token",
+            client_id=_auth_provider.client_id,
+            client_secret=_auth_provider.client_secret,
+            scopes=token_response.get("scope", "").split() if token_response.get("scope") else None,
+            expiry=datetime.utcnow() + timedelta(seconds=token_response.get("expires_in", 3600)),
+            session_id=session_id,
+            mcp_session_id=mcp_session_id,
+        )
+        
+        if mcp_session_id:
+            logger.info(f"Stored token session for {user_email} with MCP session {mcp_session_id}")
+        else:
+            logger.info(f"Stored token session for {user_email}")
+        return session_id
+        
+    except Exception as e:
+        logger.error(f"Failed to store token session: {e}")
+        return ""
\ No newline at end of file
diff --git a/auth/oauth21_integration.py b/auth/oauth21_integration.py
new file mode 100644
index 0000000..567dc2f
--- /dev/null
+++ b/auth/oauth21_integration.py
@@ -0,0 +1,203 @@
+"""
+OAuth 2.1 Integration for Google Services
+
+This module provides integration between FastMCP OAuth sessions and Google services,
+allowing authenticated sessions to be passed through to Google API calls.
+"""
+
+import asyncio
+import logging
+from typing import Optional, Tuple, Any, Dict
+
+from googleapiclient.discovery import build
+
+from auth.google_auth import (
+    GoogleAuthenticationError,
+)
+
+logger = logging.getLogger(__name__)
+
+
+class OAuth21GoogleServiceBuilder:
+    """Builds Google services using FastMCP OAuth authenticated sessions."""
+    
+    def __init__(self):
+        """
+        Initialize the service builder.
+        """
+        self._service_cache: Dict[str, Tuple[Any, str]] = {}
+    
+    def extract_session_from_context(self, context: Optional[Dict[str, Any]] = None) -> Optional[str]:
+        """
+        Extract session ID from various context sources.
+        
+        Args:
+            context: Context dictionary that may contain session information
+            
+        Returns:
+            Session ID if found, None otherwise
+        """
+        if not context:
+            return None
+            
+        # Try to extract from OAuth 2.1 auth context
+        if "auth_context" in context and hasattr(context["auth_context"], "session_id"):
+            return context["auth_context"].session_id
+            
+        # Try direct session_id
+        if "session_id" in context:
+            return context["session_id"]
+            
+        # Try from request state
+        if "request" in context:
+            request = context["request"]
+            if hasattr(request, "state") and hasattr(request.state, "auth"):
+                auth_ctx = request.state.auth
+                if hasattr(auth_ctx, "session_id"):
+                    return auth_ctx.session_id
+                    
+        return None
+    
+    async def get_authenticated_service_with_session(
+        self,
+        service_name: str,
+        version: str,
+        tool_name: str,
+        user_google_email: str,
+        required_scopes: list[str],
+        session_id: Optional[str] = None,
+        auth_context: Optional[Any] = None,
+    ) -> Tuple[Any, str]:
+        """
+        Get authenticated Google service using OAuth 2.1 session if available.
+        
+        Args:
+            service_name: Google service name (e.g., "gmail", "drive")
+            version: API version (e.g., "v1", "v3")
+            tool_name: Name of the tool for logging
+            user_google_email: User's Google email
+            required_scopes: Required OAuth scopes
+            session_id: OAuth 2.1 session ID
+            auth_context: OAuth 2.1 authentication context
+            
+        Returns:
+            Tuple of (service instance, actual user email)
+            
+        Raises:
+            GoogleAuthenticationError: If authentication fails
+        """
+        cache_key = f"{user_google_email}:{service_name}:{version}:{':'.join(sorted(required_scopes))}"
+        
+        # Check cache first
+        if cache_key in self._service_cache:
+            logger.debug(f"[{tool_name}] Using cached service for {user_google_email}")
+            return self._service_cache[cache_key]
+        
+        try:
+            # First check the global OAuth 2.1 session store
+            from auth.oauth21_session_store import get_oauth21_session_store
+            store = get_oauth21_session_store()
+            credentials = store.get_credentials(user_google_email)
+            
+            if credentials and credentials.valid:
+                logger.info(f"[{tool_name}] Found OAuth 2.1 credentials in global store for {user_google_email}")
+                
+                # Build the service
+                service = await asyncio.to_thread(
+                    build, service_name, version, credentials=credentials
+                )
+                
+                # Cache the service
+                self._service_cache[cache_key] = (service, user_google_email)
+                
+                return service, user_google_email
+            
+            # OAuth 2.1 is now handled by FastMCP - removed legacy auth_layer code
+            
+            # Fall back to legacy authentication
+            logger.debug(f"[{tool_name}] Falling back to legacy authentication for {user_google_email}")
+            from auth.google_auth import get_authenticated_google_service as legacy_get_service
+            
+            return await legacy_get_service(
+                service_name=service_name,
+                version=version,
+                tool_name=tool_name,
+                user_google_email=user_google_email,
+                required_scopes=required_scopes,
+            )
+            
+        except Exception as e:
+            logger.error(f"[{tool_name}] Authentication failed for {user_google_email}: {e}")
+            raise GoogleAuthenticationError(
+                f"Failed to authenticate for {service_name}: {str(e)}"
+            )
+    
+    def clear_cache(self):
+        """Clear the service cache."""
+        self._service_cache.clear()
+        logger.debug("Cleared OAuth 2.1 service cache")
+
+
+# Global instance
+_global_service_builder: Optional[OAuth21GoogleServiceBuilder] = None
+
+
+def get_oauth21_service_builder() -> OAuth21GoogleServiceBuilder:
+    """Get the global OAuth 2.1 service builder instance."""
+    global _global_service_builder
+    if _global_service_builder is None:
+        _global_service_builder = OAuth21GoogleServiceBuilder()
+    return _global_service_builder
+
+
+def set_auth_layer(auth_layer):
+    """
+    Legacy compatibility function - no longer needed with FastMCP auth.
+    """
+    logger.info("set_auth_layer called - OAuth is now handled by FastMCP")
+
+
+async def get_authenticated_google_service_oauth21(
+    service_name: str,
+    version: str,
+    tool_name: str,
+    user_google_email: str,
+    required_scopes: list[str],
+    context: Optional[Dict[str, Any]] = None,
+) -> Tuple[Any, str]:
+    """
+    Enhanced version of get_authenticated_google_service that supports OAuth 2.1.
+    
+    This function checks for OAuth 2.1 session context and uses it if available,
+    otherwise falls back to legacy authentication.
+    
+    Args:
+        service_name: Google service name
+        version: API version
+        tool_name: Tool name for logging
+        user_google_email: User's Google email
+        required_scopes: Required OAuth scopes
+        context: Optional context containing session information
+        
+    Returns:
+        Tuple of (service instance, actual user email)
+    """
+    builder = get_oauth21_service_builder()
+    
+    # FastMCP handles context now - extract any session info
+    session_id = None
+    auth_context = None
+    
+    if context:
+        session_id = builder.extract_session_from_context(context)
+        auth_context = context.get("auth_context")
+    
+    return await builder.get_authenticated_service_with_session(
+        service_name=service_name,
+        version=version,
+        tool_name=tool_name,
+        user_google_email=user_google_email,
+        required_scopes=required_scopes,
+        session_id=session_id,
+        auth_context=auth_context,
+    )
\ No newline at end of file
diff --git a/auth/oauth21_session_store.py b/auth/oauth21_session_store.py
new file mode 100644
index 0000000..72575c6
--- /dev/null
+++ b/auth/oauth21_session_store.py
@@ -0,0 +1,194 @@
+"""
+OAuth 2.1 Session Store for Google Services
+
+This module provides a global store for OAuth 2.1 authenticated sessions
+that can be accessed by Google service decorators.
+"""
+
+import logging
+from typing import Dict, Optional, Any
+from threading import RLock
+
+from google.oauth2.credentials import Credentials
+
+logger = logging.getLogger(__name__)
+
+
+class OAuth21SessionStore:
+    """
+    Global store for OAuth 2.1 authenticated sessions.
+    
+    This store maintains a mapping of user emails to their OAuth 2.1
+    authenticated credentials, allowing Google services to access them.
+    It also maintains a mapping from FastMCP session IDs to user emails.
+    """
+    
+    def __init__(self):
+        self._sessions: Dict[str, Dict[str, Any]] = {}
+        self._mcp_session_mapping: Dict[str, str] = {}  # Maps FastMCP session ID -> user email
+        self._lock = RLock()
+    
+    def store_session(
+        self,
+        user_email: str,
+        access_token: str,
+        refresh_token: Optional[str] = None,
+        token_uri: str = "https://oauth2.googleapis.com/token",
+        client_id: Optional[str] = None,
+        client_secret: Optional[str] = None,
+        scopes: Optional[list] = None,
+        expiry: Optional[Any] = None,
+        session_id: Optional[str] = None,
+        mcp_session_id: Optional[str] = None,
+    ):
+        """
+        Store OAuth 2.1 session information.
+        
+        Args:
+            user_email: User's email address
+            access_token: OAuth 2.1 access token
+            refresh_token: OAuth 2.1 refresh token
+            token_uri: Token endpoint URI
+            client_id: OAuth client ID
+            client_secret: OAuth client secret
+            scopes: List of granted scopes
+            expiry: Token expiry time
+            session_id: OAuth 2.1 session ID
+            mcp_session_id: FastMCP session ID to map to this user
+        """
+        with self._lock:
+            session_info = {
+                "access_token": access_token,
+                "refresh_token": refresh_token,
+                "token_uri": token_uri,
+                "client_id": client_id,
+                "client_secret": client_secret,
+                "scopes": scopes or [],
+                "expiry": expiry,
+                "session_id": session_id,
+                "mcp_session_id": mcp_session_id,
+            }
+            
+            self._sessions[user_email] = session_info
+            
+            # Store MCP session mapping if provided
+            if mcp_session_id:
+                self._mcp_session_mapping[mcp_session_id] = user_email
+                logger.info(f"Stored OAuth 2.1 session for {user_email} (session_id: {session_id}, mcp_session_id: {mcp_session_id})")
+            else:
+                logger.info(f"Stored OAuth 2.1 session for {user_email} (session_id: {session_id})")
+    
+    def get_credentials(self, user_email: str) -> Optional[Credentials]:
+        """
+        Get Google credentials for a user from OAuth 2.1 session.
+        
+        Args:
+            user_email: User's email address
+            
+        Returns:
+            Google Credentials object or None
+        """
+        with self._lock:
+            session_info = self._sessions.get(user_email)
+            if not session_info:
+                logger.debug(f"No OAuth 2.1 session found for {user_email}")
+                return None
+            
+            try:
+                # Create Google credentials from session info
+                credentials = Credentials(
+                    token=session_info["access_token"],
+                    refresh_token=session_info.get("refresh_token"),
+                    token_uri=session_info["token_uri"],
+                    client_id=session_info.get("client_id"),
+                    client_secret=session_info.get("client_secret"),
+                    scopes=session_info.get("scopes", []),
+                    expiry=session_info.get("expiry"),
+                )
+                
+                logger.debug(f"Retrieved OAuth 2.1 credentials for {user_email}")
+                return credentials
+                
+            except Exception as e:
+                logger.error(f"Failed to create credentials for {user_email}: {e}")
+                return None
+    
+    def get_credentials_by_mcp_session(self, mcp_session_id: str) -> Optional[Credentials]:
+        """
+        Get Google credentials using FastMCP session ID.
+        
+        Args:
+            mcp_session_id: FastMCP session ID
+            
+        Returns:
+            Google Credentials object or None
+        """
+        with self._lock:
+            # Look up user email from MCP session mapping
+            user_email = self._mcp_session_mapping.get(mcp_session_id)
+            if not user_email:
+                logger.debug(f"No user mapping found for MCP session {mcp_session_id}")
+                return None
+            
+            logger.debug(f"Found user {user_email} for MCP session {mcp_session_id}")
+            return self.get_credentials(user_email)
+    
+    def get_user_by_mcp_session(self, mcp_session_id: str) -> Optional[str]:
+        """
+        Get user email by FastMCP session ID.
+        
+        Args:
+            mcp_session_id: FastMCP session ID
+            
+        Returns:
+            User email or None
+        """
+        with self._lock:
+            return self._mcp_session_mapping.get(mcp_session_id)
+    
+    def remove_session(self, user_email: str):
+        """Remove session for a user."""
+        with self._lock:
+            if user_email in self._sessions:
+                # Get MCP session ID if exists to clean up mapping
+                session_info = self._sessions.get(user_email, {})
+                mcp_session_id = session_info.get("mcp_session_id")
+                
+                # Remove from sessions
+                del self._sessions[user_email]
+                
+                # Remove from MCP mapping if exists
+                if mcp_session_id and mcp_session_id in self._mcp_session_mapping:
+                    del self._mcp_session_mapping[mcp_session_id]
+                    logger.info(f"Removed OAuth 2.1 session for {user_email} and MCP mapping for {mcp_session_id}")
+                else:
+                    logger.info(f"Removed OAuth 2.1 session for {user_email}")
+    
+    def has_session(self, user_email: str) -> bool:
+        """Check if a user has an active session."""
+        with self._lock:
+            return user_email in self._sessions
+    
+    def has_mcp_session(self, mcp_session_id: str) -> bool:
+        """Check if an MCP session has an associated user session."""
+        with self._lock:
+            return mcp_session_id in self._mcp_session_mapping
+    
+    def get_stats(self) -> Dict[str, Any]:
+        """Get store statistics."""
+        with self._lock:
+            return {
+                "total_sessions": len(self._sessions),
+                "users": list(self._sessions.keys()),
+                "mcp_session_mappings": len(self._mcp_session_mapping),
+                "mcp_sessions": list(self._mcp_session_mapping.keys()),
+            }
+
+
+# Global instance
+_global_store = OAuth21SessionStore()
+
+
+def get_oauth21_session_store() -> OAuth21SessionStore:
+    """Get the global OAuth 2.1 session store."""
+    return _global_store
\ No newline at end of file
diff --git a/auth/oauth_callback_server.py b/auth/oauth_callback_server.py
index e8ecc88..32d48c9 100644
--- a/auth/oauth_callback_server.py
+++ b/auth/oauth_callback_server.py
@@ -17,7 +17,7 @@ from fastapi import FastAPI, Request
 from typing import Optional
 from urllib.parse import urlparse
 
-from auth.google_auth import handle_auth_callback, check_client_secrets
+# Import moved inside functions to avoid circular import
 from auth.scopes import SCOPES
 from auth.oauth_responses import create_error_response, create_success_response, create_server_error_response
 
@@ -62,6 +62,7 @@ class MinimalOAuthServer:
 
             try:
                 # Check if we have credentials available (environment variables or file)
+                from auth.google_auth import check_client_secrets
                 error_message = check_client_secrets()
                 if error_message:
                     return create_server_error_response(error_message)
@@ -71,6 +72,7 @@ class MinimalOAuthServer:
                 # Session ID tracking removed - not needed
 
                 # Exchange code for credentials
+                from auth.google_auth import handle_auth_callback
                 redirect_uri = get_oauth_redirect_uri(port=self.port, base_uri=self.base_uri)
                 verified_user_id, credentials = handle_auth_callback(
                     scopes=SCOPES,
diff --git a/auth/scopes.py b/auth/scopes.py
index 516c20e..43eaa54 100644
--- a/auth/scopes.py
+++ b/auth/scopes.py
@@ -10,11 +10,14 @@ logger = logging.getLogger(__name__)
 
 # Individual OAuth Scope Constants
 USERINFO_EMAIL_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
+USERINFO_PROFILE_SCOPE = 'https://www.googleapis.com/auth/userinfo.profile'
 OPENID_SCOPE = 'openid'
+CALENDAR_SCOPE = 'https://www.googleapis.com/auth/calendar'
 CALENDAR_READONLY_SCOPE = 'https://www.googleapis.com/auth/calendar.readonly'
 CALENDAR_EVENTS_SCOPE = 'https://www.googleapis.com/auth/calendar.events'
 
 # Google Drive scopes
+DRIVE_SCOPE = 'https://www.googleapis.com/auth/drive'
 DRIVE_READONLY_SCOPE = 'https://www.googleapis.com/auth/drive.readonly'
 DRIVE_FILE_SCOPE = 'https://www.googleapis.com/auth/drive.file'
 
@@ -57,6 +60,7 @@ CUSTOM_SEARCH_SCOPE = 'https://www.googleapis.com/auth/cse'
 # Base OAuth scopes required for user identification
 BASE_SCOPES = [
     USERINFO_EMAIL_SCOPE,
+    USERINFO_PROFILE_SCOPE,
     OPENID_SCOPE
 ]
 
@@ -67,11 +71,13 @@ DOCS_SCOPES = [
 ]
 
 CALENDAR_SCOPES = [
+    CALENDAR_SCOPE,
     CALENDAR_READONLY_SCOPE,
     CALENDAR_EVENTS_SCOPE
 ]
 
 DRIVE_SCOPES = [
+    DRIVE_SCOPE,
     DRIVE_READONLY_SCOPE,
     DRIVE_FILE_SCOPE
 ]
diff --git a/auth/service_decorator.py b/auth/service_decorator.py
index 91d10ed..7d57435 100644
--- a/auth/service_decorator.py
+++ b/auth/service_decorator.py
@@ -18,6 +18,41 @@ from auth.scopes import (
     TASKS_SCOPE, TASKS_READONLY_SCOPE,
     CUSTOM_SEARCH_SCOPE
 )
+from auth.session_context import get_session_context
+
+# OAuth 2.1 integration is now handled by FastMCP auth
+OAUTH21_INTEGRATION_AVAILABLE = True
+
+async def get_authenticated_google_service_oauth21(
+    service_name: str,
+    version: str,
+    tool_name: str,
+    user_google_email: str,
+    required_scopes: List[str],
+) -> tuple[Any, str]:
+    """
+    OAuth 2.1 authentication using the session store.
+    """
+    from auth.oauth21_session_store import get_oauth21_session_store
+    from googleapiclient.discovery import build
+    
+    store = get_oauth21_session_store()
+    credentials = store.get_credentials(user_google_email)
+    
+    if not credentials:
+        from auth.google_auth import GoogleAuthenticationError
+        raise GoogleAuthenticationError(f"No OAuth 2.1 credentials found for {user_google_email}")
+    
+    # Check scopes
+    if not all(scope in credentials.scopes for scope in required_scopes):
+        from auth.google_auth import GoogleAuthenticationError
+        raise GoogleAuthenticationError(f"OAuth 2.1 credentials lack required scopes. Need: {required_scopes}, Have: {credentials.scopes}")
+    
+    # Build service
+    service = build(service_name, version, credentials=credentials)
+    logger.info(f"[{tool_name}] Successfully authenticated {service_name} service using OAuth 2.1 for user: {user_google_email}")
+    
+    return service, user_google_email
 
 logger = logging.getLogger(__name__)
 
@@ -256,13 +291,73 @@ def require_google_service(
             if service is None:
                 try:
                     tool_name = func.__name__
-                    service, actual_user_email = await get_authenticated_google_service(
-                        service_name=service_name,
-                        version=service_version,
-                        tool_name=tool_name,
-                        user_google_email=user_google_email,
-                        required_scopes=resolved_scopes,
-                    )
+                    
+                    # Check if we have OAuth 2.1 credentials for this user
+                    session_ctx = None
+                    
+                    # Try to get FastMCP session ID (for future use)
+                    mcp_session_id = None
+                    session_ctx = None
+                    try:
+                        from fastmcp.server.dependencies import get_context
+                        fastmcp_ctx = get_context()
+                        if fastmcp_ctx and hasattr(fastmcp_ctx, 'session_id'):
+                            mcp_session_id = fastmcp_ctx.session_id
+                            logger.debug(f"[{tool_name}] Got FastMCP session ID: {mcp_session_id}")
+                            
+                            # Set FastMCP session ID in context variable for propagation
+                            from core.context import set_fastmcp_session_id
+                            set_fastmcp_session_id(mcp_session_id)
+                            
+                            # Create session context using FastMCP session ID
+                            from auth.session_context import SessionContext
+                            session_ctx = SessionContext(
+                                session_id=mcp_session_id,
+                                user_id=user_google_email,
+                                metadata={"fastmcp_session_id": mcp_session_id, "user_email": user_google_email}
+                            )
+                    except Exception as e:
+                        logger.debug(f"[{tool_name}] Could not get FastMCP context: {e}")
+                    
+                    # Fallback to legacy session context if available
+                    if not session_ctx and OAUTH21_INTEGRATION_AVAILABLE:
+                        session_ctx = get_session_context()
+                    
+                    # Also check if user has credentials in OAuth 2.1 store
+                    has_oauth21_creds = False
+                    if OAUTH21_INTEGRATION_AVAILABLE:
+                        try:
+                            from auth.oauth21_session_store import get_oauth21_session_store
+                            store = get_oauth21_session_store()
+                            has_oauth21_creds = store.has_session(user_google_email)
+                        except Exception:
+                            pass
+                    
+                    session_id_for_log = mcp_session_id if mcp_session_id else (session_ctx.session_id if session_ctx else 'None')
+                    logger.info(f"[{tool_name}] OAuth 2.1 available: {OAUTH21_INTEGRATION_AVAILABLE}, FastMCP Session ID: {mcp_session_id}, Session context: {session_ctx}, Session ID: {session_id_for_log}, Has OAuth21 creds: {has_oauth21_creds}")
+                    
+                    if OAUTH21_INTEGRATION_AVAILABLE and (session_ctx or has_oauth21_creds):
+                        logger.info(f"[{tool_name}] Using OAuth 2.1 authentication")
+                        service, actual_user_email = await get_authenticated_google_service_oauth21(
+                            service_name=service_name,
+                            version=service_version,
+                            tool_name=tool_name,
+                            user_google_email=user_google_email,
+                            required_scopes=resolved_scopes,
+                        )
+                    else:
+                        # Fall back to legacy authentication
+                        session_id_for_legacy = mcp_session_id if mcp_session_id else (session_ctx.session_id if session_ctx else None)
+                        logger.info(f"[{tool_name}] Calling get_authenticated_google_service with session_id_for_legacy: {session_id_for_legacy}")
+                        service, actual_user_email = await get_authenticated_google_service(
+                            service_name=service_name,
+                            version=service_version,
+                            tool_name=tool_name,
+                            user_google_email=user_google_email,
+                            required_scopes=resolved_scopes,
+                            session_id=session_id_for_legacy,
+                        )
+                    
                     if cache_enabled:
                         cache_key = _get_cache_key(user_google_email, service_name, service_version, resolved_scopes)
                         _cache_service(cache_key, service, actual_user_email)
@@ -340,13 +435,26 @@ def require_multiple_services(service_configs: List[Dict[str, Any]]):
 
                 try:
                     tool_name = func.__name__
-                    service, _ = await get_authenticated_google_service(
-                        service_name=service_name,
-                        version=service_version,
-                        tool_name=tool_name,
-                        user_google_email=user_google_email,
-                        required_scopes=resolved_scopes,
-                    )
+                    
+                    # Try OAuth 2.1 integration first if available
+                    if OAUTH21_INTEGRATION_AVAILABLE and get_session_context():
+                        logger.debug(f"Attempting OAuth 2.1 authentication for {tool_name} ({service_type})")
+                        service, _ = await get_authenticated_google_service_oauth21(
+                            service_name=service_name,
+                            version=service_version,
+                            tool_name=tool_name,
+                            user_google_email=user_google_email,
+                            required_scopes=resolved_scopes,
+                        )
+                    else:
+                        # Fall back to legacy authentication
+                        service, _ = await get_authenticated_google_service(
+                            service_name=service_name,
+                            version=service_version,
+                            tool_name=tool_name,
+                            user_google_email=user_google_email,
+                            required_scopes=resolved_scopes,
+                        )
 
                     # Inject service with specified parameter name
                     kwargs[param_name] = service
diff --git a/auth/service_decorator_oauth21.py.bak b/auth/service_decorator_oauth21.py.bak
new file mode 100644
index 0000000..c4b16a8
--- /dev/null
+++ b/auth/service_decorator_oauth21.py.bak
@@ -0,0 +1,216 @@
+"""
+Enhanced Service Decorator with OAuth 2.1 Support
+
+This module provides an enhanced version of the service decorator that can
+extract and use OAuth 2.1 session context from FastMCP.
+"""
+
+import inspect
+import logging
+from functools import wraps
+from typing import Dict, List, Optional, Any, Callable, Union
+from datetime import datetime, timedelta
+
+from google.auth.exceptions import RefreshError
+
+from auth.service_decorator import (
+    SERVICE_CONFIGS,
+    SCOPE_GROUPS,
+    _resolve_scopes,
+    _get_cache_key,
+    _is_cache_valid,
+    _handle_token_refresh_error,
+    _get_cached_service,
+    _cache_service,
+    GoogleAuthenticationError,
+)
+from auth.oauth21_integration import get_authenticated_google_service_oauth21
+
+logger = logging.getLogger(__name__)
+
+
+def _extract_context_from_args(args: tuple, kwargs: dict, sig: inspect.Signature) -> Optional[Dict[str, Any]]:
+    """
+    Extract FastMCP Context from function arguments.
+    
+    Args:
+        args: Positional arguments
+        kwargs: Keyword arguments
+        sig: Function signature
+        
+    Returns:
+        Context information if found
+    """
+    param_names = list(sig.parameters.keys())
+    
+    # Check for Context type annotation
+    for param_name, param in sig.parameters.items():
+        if param.annotation and "Context" in str(param.annotation):
+            # Found Context parameter
+            if param_name in kwargs:
+                ctx = kwargs[param_name]
+            else:
+                try:
+                    param_index = param_names.index(param_name)
+                    if param_index < len(args):
+                        ctx = args[param_index]
+                    else:
+                        continue
+                except ValueError:
+                    continue
+            
+            # Extract relevant information from Context
+            if ctx:
+                context_info = {}
+                
+                # Try to get session_id
+                if hasattr(ctx, "session_id"):
+                    context_info["session_id"] = ctx.session_id
+                
+                # Try to get request object
+                if hasattr(ctx, "request"):
+                    context_info["request"] = ctx.request
+                    
+                # Try to get auth context from request state
+                if hasattr(ctx, "request") and hasattr(ctx.request, "state"):
+                    if hasattr(ctx.request.state, "auth"):
+                        context_info["auth_context"] = ctx.request.state.auth
+                
+                return context_info if context_info else None
+    
+    return None
+
+
+def require_google_service_oauth21(
+    service_type: str,
+    scopes: Union[str, List[str]],
+    version: Optional[str] = None,
+    cache_enabled: bool = True,
+    fallback_to_legacy: bool = True
+):
+    """
+    Enhanced decorator that injects authenticated Google service with OAuth 2.1 support.
+    
+    This decorator checks for FastMCP Context in the function parameters and uses
+    OAuth 2.1 session information if available, otherwise falls back to legacy auth.
+    
+    Args:
+        service_type: Type of Google service (e.g., 'gmail', 'drive')
+        scopes: Required scopes or scope aliases
+        version: API version (optional, uses default if not specified)
+        cache_enabled: Whether to cache service instances
+        fallback_to_legacy: Whether to fall back to legacy auth if OAuth 2.1 fails
+        
+    Usage:
+        @require_google_service_oauth21("gmail", "gmail_read")
+        async def search_emails(service, user_google_email: str, ctx: Context):
+            # service is automatically injected
+            # ctx provides OAuth 2.1 session context
+    """
+    def decorator(func: Callable) -> Callable:
+        # Get service configuration
+        if service_type not in SERVICE_CONFIGS:
+            raise ValueError(f"Unknown service type: {service_type}")
+        
+        service_config = SERVICE_CONFIGS[service_type]
+        service_name = service_config["service"]
+        service_version = version or service_config["version"]
+        
+        # Resolve scopes
+        resolved_scopes = _resolve_scopes(scopes)
+        
+        # Create wrapper with modified signature
+        sig = inspect.signature(func)
+        params = list(sig.parameters.values())
+        
+        # Remove 'service' parameter from signature
+        wrapper_params = [p for p in params if p.name != 'service']
+        wrapper_sig = sig.replace(parameters=wrapper_params)
+        
+        @wraps(func)
+        async def wrapper(*args, **kwargs):
+            # Extract user_google_email
+            user_google_email = None
+            if 'user_google_email' in kwargs:
+                user_google_email = kwargs['user_google_email']
+            else:
+                param_names = list(sig.parameters.keys())
+                try:
+                    user_email_index = param_names.index('user_google_email')
+                    if user_email_index < len(args):
+                        user_google_email = args[user_email_index]
+                except ValueError:
+                    pass
+            
+            if not user_google_email:
+                raise ValueError("user_google_email parameter is required")
+            
+            # Extract context information
+            context = _extract_context_from_args(args, kwargs, sig)
+            
+            service = None
+            actual_user_email = user_google_email
+            
+            # Check cache if enabled
+            if cache_enabled:
+                cache_key = _get_cache_key(user_google_email, service_name, service_version, resolved_scopes)
+                cached_result = _get_cached_service(cache_key)
+                if cached_result:
+                    service, actual_user_email = cached_result
+                    logger.debug(f"Using cached service for {user_google_email}")
+            
+            if service is None:
+                try:
+                    tool_name = func.__name__
+                    
+                    # Try OAuth 2.1 authentication with context
+                    if context:
+                        logger.debug(f"Attempting OAuth 2.1 authentication for {tool_name}")
+                        service, actual_user_email = await get_authenticated_google_service_oauth21(
+                            service_name=service_name,
+                            version=service_version,
+                            tool_name=tool_name,
+                            user_google_email=user_google_email,
+                            required_scopes=resolved_scopes,
+                            context=context,
+                        )
+                    elif fallback_to_legacy:
+                        # Fall back to legacy authentication
+                        logger.debug(f"Using legacy authentication for {tool_name}")
+                        from auth.google_auth import get_authenticated_google_service
+                        service, actual_user_email = await get_authenticated_google_service(
+                            service_name=service_name,
+                            version=service_version,
+                            tool_name=tool_name,
+                            user_google_email=user_google_email,
+                            required_scopes=resolved_scopes,
+                        )
+                    else:
+                        raise GoogleAuthenticationError(
+                            "OAuth 2.1 context required but not found"
+                        )
+                    
+                    # Cache the service if enabled
+                    if cache_enabled and service:
+                        cache_key = _get_cache_key(user_google_email, service_name, service_version, resolved_scopes)
+                        _cache_service(cache_key, service, actual_user_email)
+                        
+                except GoogleAuthenticationError as e:
+                    raise Exception(str(e))
+            
+            # Call the original function with the service object injected
+            try:
+                return await func(service, *args, **kwargs)
+            except RefreshError as e:
+                error_message = _handle_token_refresh_error(e, actual_user_email, service_name)
+                raise Exception(error_message)
+        
+        # Set the wrapper's signature to the one without 'service'
+        wrapper.__signature__ = wrapper_sig
+        return wrapper
+    
+    return decorator
+
+
+# Alias for backward compatibility
+require_google_service = require_google_service_oauth21
\ No newline at end of file
diff --git a/auth/session_context.py b/auth/session_context.py
new file mode 100644
index 0000000..2a2e6e9
--- /dev/null
+++ b/auth/session_context.py
@@ -0,0 +1,116 @@
+"""
+Session Context Management for OAuth 2.1 Integration
+
+This module provides thread-local storage for OAuth 2.1 session context,
+allowing tool functions to access the current authenticated session.
+"""
+
+import contextvars
+import logging
+from typing import Optional, Dict, Any
+from dataclasses import dataclass
+
+logger = logging.getLogger(__name__)
+
+# Context variable to store the current session information
+_current_session_context: contextvars.ContextVar[Optional['SessionContext']] = contextvars.ContextVar(
+    'current_session_context',
+    default=None
+)
+
+
+@dataclass
+class SessionContext:
+    """Container for session-related information."""
+    session_id: Optional[str] = None
+    user_id: Optional[str] = None
+    auth_context: Optional[Any] = None
+    request: Optional[Any] = None
+    metadata: Dict[str, Any] = None
+
+    def __post_init__(self):
+        if self.metadata is None:
+            self.metadata = {}
+
+
+def set_session_context(context: Optional[SessionContext]):
+    """
+    Set the current session context.
+
+    Args:
+        context: The session context to set
+    """
+    _current_session_context.set(context)
+    if context:
+        logger.debug(f"Set session context: session_id={context.session_id}, user_id={context.user_id}")
+    else:
+        logger.debug("Cleared session context")
+
+
+def get_session_context() -> Optional[SessionContext]:
+    """
+    Get the current session context.
+
+    Returns:
+        The current session context or None
+    """
+    return _current_session_context.get()
+
+
+def clear_session_context():
+    """Clear the current session context."""
+    set_session_context(None)
+
+
+class SessionContextManager:
+    """
+    Context manager for temporarily setting session context.
+
+    Usage:
+        with SessionContextManager(session_context):
+            # Code that needs access to session context
+            pass
+    """
+
+    def __init__(self, context: Optional[SessionContext]):
+        self.context = context
+        self.token = None
+
+    def __enter__(self):
+        """Set the session context."""
+        self.token = _current_session_context.set(self.context)
+        return self.context
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        """Reset the session context."""
+        if self.token:
+            _current_session_context.reset(self.token)
+
+
+def extract_session_from_headers(headers: Dict[str, str]) -> Optional[str]:
+    """
+    Extract session ID from request headers.
+
+    Args:
+        headers: Request headers
+
+    Returns:
+        Session ID if found
+    """
+    # Try different header names
+    session_id = headers.get("mcp-session-id") or headers.get("Mcp-Session-Id")
+    if session_id:
+        return session_id
+
+    session_id = headers.get("x-session-id") or headers.get("X-Session-ID")
+    if session_id:
+        return session_id
+
+    # Try Authorization header for Bearer token
+    auth_header = headers.get("authorization") or headers.get("Authorization")
+    if auth_header and auth_header.lower().startswith("bearer "):
+        # For now, we can't extract session from bearer token without the full context
+        # This would need to be handled by the OAuth 2.1 middleware
+        pass
+
+    return None
\ No newline at end of file
diff --git a/core/config.py b/core/config.py
new file mode 100644
index 0000000..2e3985b
--- /dev/null
+++ b/core/config.py
@@ -0,0 +1,32 @@
+"""
+Shared configuration for Google Workspace MCP server.
+This module holds configuration values that need to be shared across modules
+to avoid circular imports.
+"""
+
+import os
+
+# Server configuration
+WORKSPACE_MCP_PORT = int(os.getenv("PORT", os.getenv("WORKSPACE_MCP_PORT", 8000)))
+WORKSPACE_MCP_BASE_URI = os.getenv("WORKSPACE_MCP_BASE_URI", "http://localhost")
+USER_GOOGLE_EMAIL = os.getenv("USER_GOOGLE_EMAIL", None)
+
+# Transport mode (will be set by main.py)
+_current_transport_mode = "stdio"  # Default to stdio
+
+
+def set_transport_mode(mode: str):
+    """Set the current transport mode for OAuth callback handling."""
+    global _current_transport_mode
+    _current_transport_mode = mode
+
+
+def get_transport_mode() -> str:
+    """Get the current transport mode."""
+    return _current_transport_mode
+
+
+def get_oauth_redirect_uri() -> str:
+    """Get OAuth redirect URI based on current configuration."""
+    # Use the standard OAuth callback path
+    return f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2callback"
\ No newline at end of file
diff --git a/core/context.py b/core/context.py
index f54fcc1..d3e0b14 100644
--- a/core/context.py
+++ b/core/context.py
@@ -7,6 +7,11 @@ _injected_oauth_credentials = contextvars.ContextVar(
     "injected_oauth_credentials", default=None
 )
 
+# Context variable to hold FastMCP session ID for the life of a single request.
+_fastmcp_session_id = contextvars.ContextVar(
+    "fastmcp_session_id", default=None
+)
+
 def get_injected_oauth_credentials():
     """
     Retrieve injected OAuth credentials for the current request context.
@@ -19,4 +24,18 @@ def set_injected_oauth_credentials(credentials: Optional[dict]):
     Set or clear the injected OAuth credentials for the current request context.
     This is called by the service decorator.
     """
-    _injected_oauth_credentials.set(credentials)
\ No newline at end of file
+    _injected_oauth_credentials.set(credentials)
+
+def get_fastmcp_session_id() -> Optional[str]:
+    """
+    Retrieve the FastMCP session ID for the current request context.
+    This is called by authentication layer to get the current session.
+    """
+    return _fastmcp_session_id.get()
+
+def set_fastmcp_session_id(session_id: Optional[str]):
+    """
+    Set or clear the FastMCP session ID for the current request context.
+    This is called when a FastMCP request starts.
+    """
+    _fastmcp_session_id.set(session_id)
\ No newline at end of file
diff --git a/core/server.py b/core/server.py
index 281fb28..b787b08 100644
--- a/core/server.py
+++ b/core/server.py
@@ -1,93 +1,153 @@
+import aiohttp
 import logging
+import jwt
+from jwt import PyJWKClient
 import os
+import time
+
 from typing import Optional
 from importlib import metadata
+from urllib.parse import urlencode
 
-from fastapi import Header
-from fastapi.responses import HTMLResponse
+from datetime import datetime, timedelta
 
+from fastapi.responses import HTMLResponse
+from fastapi.responses import JSONResponse
 
 from mcp.server.fastmcp import FastMCP
+from starlette.applications import Starlette
 from starlette.requests import Request
+from starlette.responses import RedirectResponse
+from starlette.middleware import Middleware
+from fastapi.middleware.cors import CORSMiddleware
 
-from auth.google_auth import handle_auth_callback, start_auth_flow, check_client_secrets
-from auth.oauth_callback_server import get_oauth_redirect_uri, ensure_oauth_callback_available
+from auth.oauth21_session_store import get_oauth21_session_store
+from auth.google_auth import handle_auth_callback, start_auth_flow, check_client_secrets, save_credentials_to_file
+from google.oauth2.credentials import Credentials
+from auth.oauth_callback_server import get_oauth_redirect_uri
+from auth.mcp_session_middleware import MCPSessionMiddleware
 from auth.oauth_responses import create_error_response, create_success_response, create_server_error_response
 
+# FastMCP OAuth imports
+from auth.fastmcp_google_auth import GoogleWorkspaceAuthProvider
+from auth.oauth21_google_bridge import set_auth_provider, store_token_session
+
 # Import shared configuration
-from auth.scopes import (
-    SCOPES,
-    USERINFO_EMAIL_SCOPE,  # noqa: F401
-    OPENID_SCOPE,  # noqa: F401
-    CALENDAR_READONLY_SCOPE,  # noqa: F401
-    CALENDAR_EVENTS_SCOPE,  # noqa: F401
-    DRIVE_READONLY_SCOPE,  # noqa: F401
-    DRIVE_FILE_SCOPE,  # noqa: F401
-    GMAIL_READONLY_SCOPE,  # noqa: F401
-    GMAIL_SEND_SCOPE,  # noqa: F401
-    GMAIL_COMPOSE_SCOPE,  # noqa: F401
-    GMAIL_MODIFY_SCOPE,  # noqa: F401
-    GMAIL_LABELS_SCOPE,  # noqa: F401
-    BASE_SCOPES,  # noqa: F401
-    CALENDAR_SCOPES,  # noqa: F401
-    DRIVE_SCOPES,  # noqa: F401
-    GMAIL_SCOPES,  # noqa: F401
-    DOCS_READONLY_SCOPE,  # noqa: F401
-    DOCS_WRITE_SCOPE,  # noqa: F401
-    CHAT_READONLY_SCOPE,  # noqa: F401
-    CHAT_WRITE_SCOPE,  # noqa: F401
-    CHAT_SPACES_SCOPE,  # noqa: F401
-    CHAT_SCOPES,  # noqa: F401
-    SHEETS_READONLY_SCOPE,  # noqa: F401
-    SHEETS_WRITE_SCOPE,  # noqa: F401
-    SHEETS_SCOPES,  # noqa: F401
-    FORMS_BODY_SCOPE,  # noqa: F401
-    FORMS_BODY_READONLY_SCOPE,  # noqa: F401
-    FORMS_RESPONSES_READONLY_SCOPE,  # noqa: F401
-    FORMS_SCOPES,  # noqa: F401
-    SLIDES_SCOPE,  # noqa: F401
-    SLIDES_READONLY_SCOPE,  # noqa: F401
-    SLIDES_SCOPES,  # noqa: F401
-    TASKS_SCOPE,  # noqa: F401
-    TASKS_READONLY_SCOPE,  # noqa: F401
-    TASKS_SCOPES,  # noqa: F401
-    CUSTOM_SEARCH_SCOPE,  # noqa: F401
-    CUSTOM_SEARCH_SCOPES,  # noqa: F401
+from auth.scopes import SCOPES
+from core.config import (
+    WORKSPACE_MCP_PORT,
+    WORKSPACE_MCP_BASE_URI,
+    USER_GOOGLE_EMAIL,
+    get_transport_mode,
+    set_transport_mode as _set_transport_mode,
+    get_oauth_redirect_uri as get_oauth_redirect_uri_for_current_mode,
 )
 
 # Configure logging
 logging.basicConfig(level=logging.INFO)
 logger = logging.getLogger(__name__)
 
-WORKSPACE_MCP_PORT = int(os.getenv("PORT", os.getenv("WORKSPACE_MCP_PORT", 8000)))
-WORKSPACE_MCP_BASE_URI = os.getenv("WORKSPACE_MCP_BASE_URI", "http://localhost")
-USER_GOOGLE_EMAIL = os.getenv("USER_GOOGLE_EMAIL", None)
+# FastMCP authentication provider instance
+_auth_provider: Optional[GoogleWorkspaceAuthProvider] = None
+
+# Create middleware configuration
+
+cors_middleware = Middleware(
+    CORSMiddleware,
+    allow_origins=["*"],  # In production, specify allowed origins
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"],
+)
+
+session_middleware = Middleware(MCPSessionMiddleware)
+
+# Custom FastMCP that adds CORS to streamable HTTP
+class CORSEnabledFastMCP(FastMCP):
+    def streamable_http_app(self) -> "Starlette":
+        """Override to add CORS and session middleware to the app."""
+        app = super().streamable_http_app()
+        # Add session middleware first (to set context before other middleware)
+        app.user_middleware.insert(0, session_middleware)
+        # Add CORS as the second middleware
+        app.user_middleware.insert(1, cors_middleware)
+        # Rebuild middleware stack
+        app.middleware_stack = app.build_middleware_stack()
+        logger.info("Added session and CORS middleware to streamable HTTP app")
+        return app
 
-# Transport mode detection (will be set by main.py)
-_current_transport_mode = "stdio"  # Default to stdio
+# Initialize auth provider for HTTP transport
+def create_auth_provider() -> Optional[GoogleWorkspaceAuthProvider]:
+    """Create auth provider if OAuth credentials are configured."""
+    if os.getenv("GOOGLE_OAUTH_CLIENT_ID") and get_transport_mode() == "streamable-http":
+        return GoogleWorkspaceAuthProvider()
+    return None
 
-# Basic MCP server instance
-server = FastMCP(
+# Basic MCP server instance - auth will be set based on transport mode
+server = CORSEnabledFastMCP(
     name="google_workspace",
     port=WORKSPACE_MCP_PORT,
-    host="0.0.0.0"
+    host="0.0.0.0",
+    auth=None  # Will be set in initialize_auth() if needed
 )
 
 def set_transport_mode(mode: str):
     """Set the current transport mode for OAuth callback handling."""
-    global _current_transport_mode
-    _current_transport_mode = mode
+    _set_transport_mode(mode)
     logger.info(f"Transport mode set to: {mode}")
 
-def get_oauth_redirect_uri_for_current_mode() -> str:
-    """Get OAuth redirect URI based on current transport mode."""
-    return get_oauth_redirect_uri(WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI)
+async def initialize_auth() -> Optional[GoogleWorkspaceAuthProvider]:
+    """Initialize FastMCP authentication if available and configured."""
+    global _auth_provider
+
+    # Only initialize auth for HTTP transport
+    if get_transport_mode() != "streamable-http":
+        logger.info("Authentication not available in stdio mode")
+        return None
+
+    # Check if OAuth is configured
+    if not os.getenv("GOOGLE_OAUTH_CLIENT_ID"):
+        logger.info("OAuth not configured (GOOGLE_OAUTH_CLIENT_ID not set)")
+        return None
+
+    try:
+        # Create and configure auth provider
+        _auth_provider = GoogleWorkspaceAuthProvider()
+
+        # Set up the bridge for Google credentials
+        set_auth_provider(_auth_provider)
+
+        # Update server auth
+        server.auth = _auth_provider
+
+        logger.info("FastMCP authentication initialized with Google Workspace provider")
+        return _auth_provider
+    except Exception as e:
+        logger.error(f"Failed to initialize authentication: {e}")
+        return None
+
+async def shutdown_auth():
+    """Shutdown authentication provider."""
+    global _auth_provider
+    if _auth_provider:
+        try:
+            # FastMCP auth providers don't need explicit shutdown
+            logger.info("Authentication provider stopped")
+        except Exception as e:
+            logger.error(f"Error stopping authentication: {e}")
+        finally:
+            _auth_provider = None
+            server.auth = None
+
+def get_auth_provider() -> Optional[GoogleWorkspaceAuthProvider]:
+    """Get the global authentication provider instance."""
+    return _auth_provider
+
 
 # Health check endpoint
 @server.custom_route("/health", methods=["GET"])
 async def health_check(request: Request):
     """Health check endpoint for container orchestration."""
-    from fastapi.responses import JSONResponse
     try:
         version = metadata.version("workspace-mcp")
     except metadata.PackageNotFoundError:
@@ -96,7 +156,7 @@ async def health_check(request: Request):
         "status": "healthy",
         "service": "workspace-mcp",
         "version": version,
-        "transport": _current_transport_mode
+        "transport": get_transport_mode()
     })
 
 
@@ -140,6 +200,24 @@ async def oauth2_callback(request: Request) -> HTMLResponse:
 
         logger.info(f"OAuth callback: Successfully authenticated user: {verified_user_id} (state: {state}).")
 
+        # Store Google credentials in OAuth 2.1 session store
+        try:
+            store = get_oauth21_session_store()
+            store.store_session(
+                user_email=verified_user_id,
+                access_token=credentials.token,
+                refresh_token=credentials.refresh_token,
+                token_uri=credentials.token_uri,
+                client_id=credentials.client_id,
+                client_secret=credentials.client_secret,
+                scopes=credentials.scopes,
+                expiry=credentials.expiry,
+                session_id=f"google-{state}",  # Use state as a pseudo session ID
+            )
+            logger.info(f"Stored Google credentials in OAuth 2.1 session store for {verified_user_id}")
+        except Exception as e:
+            logger.error(f"Failed to store Google credentials in OAuth 2.1 store: {e}")
+
         # Return success page using shared template
         return create_success_response(verified_user_id)
 
@@ -191,8 +269,9 @@ async def start_google_auth(
     logger.info(f"Tool 'start_google_auth' invoked for user_google_email: '{user_google_email}', service: '{service_name}'.")
 
     # Ensure OAuth callback is available for current transport mode
+    from auth.oauth_callback_server import ensure_oauth_callback_available
     redirect_uri = get_oauth_redirect_uri_for_current_mode()
-    success, error_msg = ensure_oauth_callback_available(_current_transport_mode, WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI)
+    success, error_msg = ensure_oauth_callback_available(get_transport_mode(), WORKSPACE_MCP_PORT, WORKSPACE_MCP_BASE_URI)
     if not success:
         if error_msg:
             raise Exception(f"Failed to start OAuth callback server: {error_msg}")
@@ -205,3 +284,382 @@ async def start_google_auth(
         redirect_uri=redirect_uri
     )
     return auth_result
+
+
+# OAuth 2.1 Discovery Endpoints
+@server.custom_route("/.well-known/oauth-protected-resource", methods=["GET", "OPTIONS"])
+async def oauth_protected_resource(request: Request):
+    """OAuth 2.1 Protected Resource Metadata endpoint."""
+    if request.method == "OPTIONS":
+        return JSONResponse(
+            content={},
+            headers={
+                "Access-Control-Allow-Origin": "*",
+                "Access-Control-Allow-Methods": "GET, OPTIONS",
+                "Access-Control-Allow-Headers": "Content-Type"
+            }
+        )
+
+    metadata = {
+        "resource": f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}",
+        "authorization_servers": [
+            f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}"
+        ],
+        "bearer_methods_supported": ["header"],
+        "scopes_supported": SCOPES,
+        "resource_documentation": "https://developers.google.com/workspace",
+        "client_registration_required": True,
+        "client_configuration_endpoint": f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/.well-known/oauth-client",
+    }
+
+    return JSONResponse(
+        content=metadata,
+        headers={
+            "Content-Type": "application/json",
+            "Access-Control-Allow-Origin": "*"
+        }
+    )
+
+
+@server.custom_route("/.well-known/oauth-authorization-server", methods=["GET", "OPTIONS"])
+async def oauth_authorization_server(request: Request):
+    """OAuth 2.1 Authorization Server Metadata endpoint."""
+    if request.method == "OPTIONS":
+        return JSONResponse(
+            content={},
+            headers={
+                "Access-Control-Allow-Origin": "*",
+                "Access-Control-Allow-Methods": "GET, OPTIONS",
+                "Access-Control-Allow-Headers": "Content-Type"
+            }
+        )
+
+    try:
+        # Fetch metadata from Google
+        async with aiohttp.ClientSession() as session:
+            url = "https://accounts.google.com/.well-known/openid-configuration"
+            async with session.get(url) as response:
+                if response.status == 200:
+                    metadata = await response.json()
+
+                    # Add OAuth 2.1 required fields
+                    metadata.setdefault("code_challenge_methods_supported", ["S256"])
+                    metadata.setdefault("pkce_required", True)
+
+                    # Override endpoints to use our proxies
+                    metadata["token_endpoint"] = f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2/token"
+                    metadata["authorization_endpoint"] = f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2/authorize"
+                    metadata["enable_dynamic_registration"] = True
+                    metadata["registration_endpoint"] = f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2/register"
+                    return JSONResponse(
+                        content=metadata,
+                        headers={
+                            "Content-Type": "application/json",
+                            "Access-Control-Allow-Origin": "*"
+                        }
+                    )
+
+        # Fallback metadata
+        return JSONResponse(
+            content={
+                "issuer": "https://accounts.google.com",
+                "authorization_endpoint": f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2/authorize",
+                "token_endpoint": f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2/token",
+                "userinfo_endpoint": "https://www.googleapis.com/oauth2/v2/userinfo",
+                "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
+                "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
+                "response_types_supported": ["code"],
+                "code_challenge_methods_supported": ["S256"],
+                "pkce_required": True,
+                "grant_types_supported": ["authorization_code", "refresh_token"],
+                "scopes_supported": SCOPES,
+                "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"]
+            },
+            headers={
+                "Content-Type": "application/json",
+                "Access-Control-Allow-Origin": "*"
+            }
+        )
+
+    except Exception as e:
+        logger.error(f"Error fetching auth server metadata: {e}")
+        return JSONResponse(
+            status_code=500,
+            content={"error": "Failed to fetch authorization server metadata"},
+            headers={"Access-Control-Allow-Origin": "*"}
+        )
+
+# OAuth client configuration endpoint
+@server.custom_route("/.well-known/oauth-client", methods=["GET", "OPTIONS"])
+async def oauth_client_config(request: Request):
+    """Return OAuth client configuration."""
+    if request.method == "OPTIONS":
+        return JSONResponse(
+            content={},
+            headers={
+                "Access-Control-Allow-Origin": "*",
+                "Access-Control-Allow-Methods": "GET, OPTIONS",
+                "Access-Control-Allow-Headers": "Content-Type"
+            }
+        )
+
+    client_id = os.getenv("GOOGLE_OAUTH_CLIENT_ID")
+    if not client_id:
+        return JSONResponse(
+            status_code=404,
+            content={"error": "OAuth not configured"},
+            headers={"Access-Control-Allow-Origin": "*"}
+        )
+
+    return JSONResponse(
+        content={
+            "client_id": client_id,
+            "client_name": "Google Workspace MCP Server",
+            "client_uri": f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}",
+            "redirect_uris": [
+                f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2callback",
+                "http://localhost:5173/auth/callback"
+            ],
+            "grant_types": ["authorization_code", "refresh_token"],
+            "response_types": ["code"],
+            "scope": " ".join(SCOPES),
+            "token_endpoint_auth_method": "client_secret_basic",
+            "code_challenge_methods": ["S256"]
+        },
+        headers={
+            "Content-Type": "application/json",
+            "Access-Control-Allow-Origin": "*"
+        }
+    )
+
+# OAuth authorization endpoint (redirect to Google)
+@server.custom_route("/oauth2/authorize", methods=["GET", "OPTIONS"])
+async def oauth_authorize(request: Request):
+    """Redirect to Google's authorization endpoint."""
+    if request.method == "OPTIONS":
+        return JSONResponse(
+            content={},
+            headers={
+                "Access-Control-Allow-Origin": "*",
+                "Access-Control-Allow-Methods": "GET, OPTIONS",
+                "Access-Control-Allow-Headers": "Content-Type"
+            }
+        )
+
+    # Get query parameters
+    params = dict(request.query_params)
+
+    # Add our client ID if not provided
+    client_id = os.getenv("GOOGLE_OAUTH_CLIENT_ID")
+    if "client_id" not in params and client_id:
+        params["client_id"] = client_id
+
+    # Ensure response_type is code
+    params["response_type"] = "code"
+
+    # Merge client scopes with our full SCOPES list
+    client_scopes = params.get("scope", "").split() if params.get("scope") else []
+    # Always include all Google Workspace scopes for full functionality
+    all_scopes = set(client_scopes) | set(SCOPES)
+    params["scope"] = " ".join(sorted(all_scopes))
+    logger.info(f"OAuth 2.1 authorization: Requesting scopes: {params['scope']}")
+
+    # Build Google authorization URL
+    google_auth_url = "https://accounts.google.com/o/oauth2/v2/auth?" + urlencode(params)
+
+    # Return redirect
+    return RedirectResponse(
+        url=google_auth_url,
+        status_code=302,
+        headers={
+            "Access-Control-Allow-Origin": "*"
+        }
+    )
+
+# Token exchange proxy endpoint
+@server.custom_route("/oauth2/token", methods=["POST", "OPTIONS"])
+async def proxy_token_exchange(request: Request):
+    """Proxy token exchange to Google to avoid CORS issues."""
+    if request.method == "OPTIONS":
+        return JSONResponse(
+            content={},
+            headers={
+                "Access-Control-Allow-Origin": "*",
+                "Access-Control-Allow-Methods": "POST, OPTIONS",
+                "Access-Control-Allow-Headers": "Content-Type, Authorization"
+            }
+        )
+    try:
+        # Get form data
+        body = await request.body()
+        content_type = request.headers.get("content-type", "application/x-www-form-urlencoded")
+
+        # Forward request to Google
+        async with aiohttp.ClientSession() as session:
+            headers = {"Content-Type": content_type}
+
+            async with session.post("https://oauth2.googleapis.com/token", data=body, headers=headers) as response:
+                response_data = await response.json()
+
+                # Log for debugging
+                if response.status != 200:
+                    logger.error(f"Token exchange failed: {response.status} - {response_data}")
+                else:
+                    logger.info("Token exchange successful")
+
+                    # Store the token session for credential bridging
+                    if "access_token" in response_data:
+                        try:
+                            # Extract user email from ID token if present
+                            if "id_token" in response_data:
+                                # Verify ID token using Google's public keys for security
+                                try:
+                                    # Get Google's public keys for verification
+                                    jwks_client = PyJWKClient("https://www.googleapis.com/oauth2/v3/certs")
+
+                                    # Get signing key from JWT header
+                                    signing_key = jwks_client.get_signing_key_from_jwt(response_data["id_token"])
+
+                                    # Verify and decode the ID token
+                                    id_token_claims = jwt.decode(
+                                        response_data["id_token"],
+                                        signing_key.key,
+                                        algorithms=["RS256"],
+                                        audience=os.getenv("GOOGLE_OAUTH_CLIENT_ID"),
+                                        issuer="https://accounts.google.com"
+                                    )
+                                    user_email = id_token_claims.get("email")
+                                except Exception as e:
+                                    logger.error(f"Failed to verify ID token: {e}")
+                                    # Fallback to unverified decode for backwards compatibility (with warning)
+                                    logger.warning("Using unverified ID token decode as fallback - this should be fixed")
+                                    id_token_claims = jwt.decode(response_data["id_token"], options={"verify_signature": False})
+                                    user_email = id_token_claims.get("email")
+
+                                if user_email:
+                                    # Store the token session
+                                    session_id = store_token_session(response_data, user_email)
+                                    logger.info(f"Stored OAuth session for {user_email} (session: {session_id})")
+
+                                    # Also create and store Google credentials
+                                    expiry = None
+                                    if "expires_in" in response_data:
+                                        # Google auth library expects timezone-naive datetime
+                                        expiry = datetime.utcnow() + timedelta(seconds=response_data["expires_in"])
+
+                                    credentials = Credentials(
+                                        token=response_data["access_token"],
+                                        refresh_token=response_data.get("refresh_token"),
+                                        token_uri="https://oauth2.googleapis.com/token",
+                                        client_id=os.getenv("GOOGLE_OAUTH_CLIENT_ID"),
+                                        client_secret=os.getenv("GOOGLE_OAUTH_CLIENT_SECRET"),
+                                        scopes=response_data.get("scope", "").split() if response_data.get("scope") else None,
+                                        expiry=expiry
+                                    )
+
+                                    # Save credentials to file for legacy auth
+                                    save_credentials_to_file(user_email, credentials)
+                                    logger.info(f"Saved Google credentials for {user_email}")
+
+                        except Exception as e:
+                            logger.error(f"Failed to store OAuth session: {e}")
+
+                return JSONResponse(
+                    status_code=response.status,
+                    content=response_data,
+                    headers={
+                        "Content-Type": "application/json",
+                        "Access-Control-Allow-Origin": "*",
+                        "Cache-Control": "no-store"
+                    }
+                )
+
+    except Exception as e:
+        logger.error(f"Error in token proxy: {e}")
+        return JSONResponse(
+            status_code=500,
+            content={"error": "server_error", "error_description": str(e)},
+            headers={"Access-Control-Allow-Origin": "*"}
+        )
+
+
+# OAuth 2.1 Dynamic Client Registration endpoint
+@server.custom_route("/oauth2/register", methods=["POST", "OPTIONS"])
+async def oauth_register(request: Request):
+    """
+    Dynamic client registration workaround endpoint.
+
+    Google doesn't support OAuth 2.1 dynamic client registration, so this endpoint
+    accepts any registration request and returns our pre-configured Google OAuth
+    credentials, allowing standards-compliant clients to work seamlessly.
+    """
+    if request.method == "OPTIONS":
+        return JSONResponse(
+            content={},
+            headers={
+                "Access-Control-Allow-Origin": "*",
+                "Access-Control-Allow-Methods": "POST, OPTIONS",
+                "Access-Control-Allow-Headers": "Content-Type, Authorization"
+            }
+        )
+
+    client_id = os.getenv("GOOGLE_OAUTH_CLIENT_ID")
+    client_secret = os.getenv("GOOGLE_OAUTH_CLIENT_SECRET")
+
+    if not client_id or not client_secret:
+        return JSONResponse(
+            status_code=400,
+            content={"error": "invalid_request", "error_description": "OAuth not configured"},
+            headers={"Access-Control-Allow-Origin": "*"}
+        )
+
+    try:
+        # Parse the registration request
+        body = await request.json()
+        logger.info(f"Dynamic client registration request received: {body}")
+
+        # Extract redirect URIs from the request or use defaults
+        redirect_uris = body.get("redirect_uris", [])
+        if not redirect_uris:
+            redirect_uris = [
+                f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2callback",
+                "http://localhost:5173/auth/callback"
+            ]
+
+        # Build the registration response with our pre-configured credentials
+        response_data = {
+            "client_id": client_id,
+            "client_secret": client_secret,
+            "client_name": body.get("client_name", "Google Workspace MCP Server"),
+            "client_uri": body.get("client_uri", f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}"),
+            "redirect_uris": redirect_uris,
+            "grant_types": body.get("grant_types", ["authorization_code", "refresh_token"]),
+            "response_types": body.get("response_types", ["code"]),
+            "scope": body.get("scope", " ".join(SCOPES)),
+            "token_endpoint_auth_method": body.get("token_endpoint_auth_method", "client_secret_basic"),
+            "code_challenge_methods": ["S256"],
+            # Additional OAuth 2.1 fields
+            "client_id_issued_at": int(time.time()),
+            "registration_access_token": "not-required",  # We don't implement client management
+            "registration_client_uri": f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/oauth2/register/{client_id}"
+        }
+
+        logger.info("Dynamic client registration successful - returning pre-configured Google credentials")
+
+        return JSONResponse(
+            status_code=201,
+            content=response_data,
+            headers={
+                "Content-Type": "application/json",
+                "Access-Control-Allow-Origin": "*",
+                "Cache-Control": "no-store"
+            }
+        )
+
+    except Exception as e:
+        logger.error(f"Error in dynamic client registration: {e}")
+        return JSONResponse(
+            status_code=400,
+            content={"error": "invalid_request", "error_description": str(e)},
+            headers={"Access-Control-Allow-Origin": "*"}
+        )
diff --git a/gdocs/docs_tools.py b/gdocs/docs_tools.py
index f868f72..822cf4f 100644
--- a/gdocs/docs_tools.py
+++ b/gdocs/docs_tools.py
@@ -101,7 +101,7 @@ async def get_doc_content(
         )
         # Tab header format constant
         TAB_HEADER_FORMAT = "\n--- TAB: {tab_name} ---\n"
-        
+
         def extract_text_from_elements(elements, tab_name=None, depth=0):
             """Extract text from document elements (paragraphs, tables, etc.)"""
             # Prevent infinite recursion by limiting depth
diff --git a/gmail/gmail_tools.py b/gmail/gmail_tools.py
index a0fbc80..895694b 100644
--- a/gmail/gmail_tools.py
+++ b/gmail/gmail_tools.py
@@ -16,12 +16,12 @@ from fastapi import Body
 
 from auth.service_decorator import require_google_service
 from core.utils import handle_http_errors
-from core.server import (
+from core.server import server
+from auth.scopes import (
     GMAIL_SEND_SCOPE,
     GMAIL_COMPOSE_SCOPE,
     GMAIL_MODIFY_SCOPE,
     GMAIL_LABELS_SCOPE,
-    server,
 )
 
 logger = logging.getLogger(__name__)
diff --git a/gsearch/search_tools.py b/gsearch/search_tools.py
index ef17e28..fd993d3 100644
--- a/gsearch/search_tools.py
+++ b/gsearch/search_tools.py
@@ -7,7 +7,7 @@ This module provides MCP tools for interacting with Google Programmable Search E
 import logging
 import asyncio
 import os
-from typing import Optional, List, Dict, Any, Literal
+from typing import Optional, List, Literal
 
 from auth.service_decorator import require_google_service
 from core.server import server
@@ -208,7 +208,7 @@ async def get_search_engine_info(
     search_info = result.get('searchInformation', {})
     if search_info:
         total_results = search_info.get('totalResults', 'Unknown')
-        confirmation_message += f"\nSearch Statistics:\n"
+        confirmation_message += "\nSearch Statistics:\n"
         confirmation_message += f"  - Total indexed results: {total_results}\n"
 
     logger.info(f"Search engine info retrieved successfully for {user_google_email}")
diff --git a/main.py b/main.py
index 7ac1fec..e9b8c78 100644
--- a/main.py
+++ b/main.py
@@ -3,11 +3,13 @@ import logging
 import os
 import sys
 from importlib import metadata
-
-# Local imports
-from core.server import server, set_transport_mode
+from dotenv import load_dotenv
+from core.server import server, set_transport_mode, initialize_auth, shutdown_auth
 from core.utils import check_credentials_directory_permissions
 
+# Load environment variables from .env file
+load_dotenv()
+
 logging.basicConfig(
     level=logging.INFO,
     format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
@@ -145,6 +147,24 @@ def main():
         # Set transport mode for OAuth callback handling
         set_transport_mode(args.transport)
 
+        # Initialize OAuth 2.1 authentication if available
+        import asyncio
+        auth_provider = None
+        try:
+            if args.transport == 'streamable-http':
+                # Only initialize OAuth 2.1 for HTTP transport
+                auth_provider = asyncio.run(initialize_auth())
+                if auth_provider:
+                    safe_print("🔐 OAuth 2.1 authentication initialized with FastMCP")
+                    safe_print(f"   Discovery endpoints available at {base_uri}:{port}/.well-known/")
+                else:
+                    safe_print("🔐 Using legacy authentication only")
+            else:
+                safe_print("🔐 OAuth authentication not available in stdio mode (using legacy auth)")
+        except Exception as e:
+            safe_print(f"⚠️  OAuth authentication initialization failed: {e}")
+            safe_print("   Falling back to legacy authentication")
+
         if args.transport == 'streamable-http':
             safe_print(f"🚀 Starting server on {base_uri}:{port}")
         else:
@@ -155,7 +175,7 @@ def main():
             if success:
                 safe_print(f"   OAuth callback server started on {base_uri}:{port}/oauth2callback")
             else:
-                warning_msg = f"   ⚠️  Warning: Failed to start OAuth callback server"
+                warning_msg = "   ⚠️  Warning: Failed to start OAuth callback server"
                 if error_msg:
                     warning_msg += f": {error_msg}"
                 safe_print(warning_msg)
@@ -164,12 +184,19 @@ def main():
         safe_print("")
 
         if args.transport == 'streamable-http':
-            # The server is already configured with port and server_url in core/server.py
+            # The server has CORS middleware built-in via CORSEnabledFastMCP
             server.run(transport="streamable-http")
         else:
             server.run()
     except KeyboardInterrupt:
         safe_print("\n👋 Server shutdown requested")
+        # Clean up OAuth 2.1 authentication
+        try:
+            if auth_provider:
+                asyncio.run(shutdown_auth())
+        except Exception as e:
+            safe_print(f"⚠️  Error during OAuth 2.1 shutdown: {e}")
+
         # Clean up OAuth callback server if running
         from auth.oauth_callback_server import cleanup_oauth_callback_server
         cleanup_oauth_callback_server()
diff --git a/pyproject.toml b/pyproject.toml
index 4b9ab18..0e64aa5 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -11,7 +11,7 @@ keywords = [ "mcp", "google", "workspace", "llm", "ai", "claude", "model", "cont
 requires-python = ">=3.10"
 dependencies = [
  "fastapi>=0.115.12",
- "fastmcp>=2.10.6",
+ "fastmcp>=2.11.0",
  "google-api-python-client>=2.168.0",
  "google-auth-httplib2>=0.2.0",
  "google-auth-oauthlib>=1.2.2",
@@ -19,6 +19,9 @@ dependencies = [
  "pyjwt>=2.10.1",
  "ruff>=0.12.4",
  "tomlkit",
+ "aiohttp>=3.9.0",
+ "cachetools>=5.3.0",
+ "cryptography>=41.0.0",
 ]
 classifiers = [
     "Development Status :: 4 - Beta",
