Files
wehub-resource-sync ec2b666284
Continuous Integration / Pre-commit Linter (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.10) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.11) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.12) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.10) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.11) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.12) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.14) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Waiting to run
Copybara PR Handler / close-imported-pr (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 13:25:13 +08:00

169 lines
5.2 KiB
Python

# 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())