# Copyright 2026 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Test script for MCP Toolset OAuth Authentication Flow. This script demonstrates the two-phase tool discovery flow: 1. First invocation: Agent tries to get tools, auth is required, returns auth request event (adk_request_credential) 2. User provides OAuth credentials (simulated) 3. Second invocation: Agent has credentials, can list and call tools Usage: # Start the MCP server first (in another terminal): PYTHONPATH=src python contributing/samples/mcp_toolset_auth/oauth_mcp_server.py # Run the demo: PYTHONPATH=src python contributing/samples/mcp_toolset_auth/main.py """ from __future__ import annotations import asyncio from agent import auth_credential from agent import auth_scheme from agent import mcp_toolset from agent import root_agent from google.adk.auth.auth_credential import AuthCredential from google.adk.auth.auth_credential import AuthCredentialTypes from google.adk.auth.auth_credential import OAuth2Auth from google.adk.auth.auth_tool import AuthConfig from google.adk.runners import Runner from google.adk.sessions.in_memory_session_service import InMemorySessionService from google.genai import types async def run_demo(): """Run demo with real MCP server.""" print('=' * 60) print('MCP Toolset OAuth Authentication Demo') print('=' * 60) print('\nNote: Make sure the MCP server is running:') print(' python oauth_mcp_server.py\n') # Create session service and runner session_service = InMemorySessionService() runner = Runner( agent=root_agent, app_name='toolset_auth_demo', session_service=session_service, ) # Create a session session = await session_service.create_session( app_name='toolset_auth_demo', user_id='test_user', ) print(f'Session created: {session.id}') print('\n--- Phase 1: Initial request (no credentials) ---\n') # First invocation - should trigger auth request user_message = 'List all users' print(f'User: {user_message}') events = [] auth_function_call_id = None max_events = 10 try: async for event in runner.run_async( session_id=session.id, user_id='test_user', new_message=types.Content( role='user', parts=[types.Part(text=user_message)], ), ): events.append(event) print(f'\nEvent from {event.author}:') if event.content and event.content.parts: for part in event.content.parts: if part.text: print(f' Text: {part.text}') if part.function_call: print(f' Function call: {part.function_call.name}') if part.function_call.name == 'adk_request_credential': auth_function_call_id = part.function_call.id if len(events) >= max_events: print(f'\n** SAFETY LIMIT ({max_events} events) **') break except Exception as e: print(f'\nError: {e}') print('Make sure the MCP server is running!') await mcp_toolset.close() return if auth_function_call_id: print('\n** Auth request detected! **') print('\n--- Phase 2: Provide OAuth credentials ---\n') # Simulate user providing OAuth credentials after completing OAuth flow auth_response = AuthConfig( auth_scheme=auth_scheme, raw_auth_credential=auth_credential, exchanged_auth_credential=AuthCredential( auth_type=AuthCredentialTypes.OAUTH2, oauth2=OAuth2Auth( access_token='test_access_token_12345', ), ), ) print('Providing access token: test_access_token_12345') auth_response_message = types.Content( role='user', parts=[ types.Part( function_response=types.FunctionResponse( name='adk_request_credential', id=auth_function_call_id, response=auth_response.model_dump(exclude_none=True), ) ) ], ) async for event in runner.run_async( session_id=session.id, user_id='test_user', new_message=auth_response_message, ): print(f'\nEvent from {event.author}:') if event.content and event.content.parts: for part in event.content.parts: if part.text: text = ( part.text[:200] + '...' if len(part.text) > 200 else part.text ) print(f' Text: {text}') if part.function_call: print(f' Function call: {part.function_call.name}') else: print('\n** No auth request - credentials may already be available **') print('\n' + '=' * 60) print('Demo completed') print('=' * 60) await mcp_toolset.close() if __name__ == '__main__': asyncio.run(run_demo())