Authorized tool calling using Google ADK
Google ADK is a framework for building AI agents. Arcade provides an integration with Google ADK to allow you to use Arcade tools in your Google ADK agents with ease.
Overview
In this guide, you’ll learn how to use Arcade to call tools using Google ADK. In particular, you’ll learn how to call tools that require user authorization.
We’ll start with a barebones example of a Google ADK agent that can only chat. Then, we’ll add tools one by one, we’ll add entire toolkits at once, and we’ll handle authorization for tools that require it.
Prerequisites
Setup your environment
Google ADK uses Python. We’ll use the uv package manager to install python, as well as the necessary dependencies.
Create a new directory for this project. This guides assumes you will create it in your home directory, but feel free to create it anywhere you like.
mkdir -p ~/auth-tool-calling-adk
cd ~/auth-tool-calling-adkCreate a new uv project, and activate the virtual environment.
uv init
source .venv/bin/activateThis will have created a .venv directory with the virtual environment, as well as a pyproject.toml file with the project metadata, and a main.py file with the entry point for the application. We’ll use the main.py file to write our code.
Install the necessary dependencies:
uv add google-adk-arcadeConfigure your API keys
Set the following environment variables:
export ARCADE_API_KEY='{arcade_api_key}'
export GOOGLE_API_KEY='YOUR_GOOGLE_API_KEY'
export GOOGLE_GENAI_USE_VERTEXAI=FALSEor create a .env file with the following contents:
# .env
ARCADE_API_KEY={arcade_api_key}
GOOGLE_API_KEY=YOUR_GOOGLE_API_KEY
GOOGLE_GENAI_USE_VERTEXAI=FALSEWe need to set GOOGLE_GENAI_USE_VERTEXAI=FALSE because we’re using the Gemini API, not Vertex AI.
Create a simple agent
We’ll start with a simple agent that can only chat.
import asyncio
from google.adk import Agent, Runner
from google.adk.artifacts import InMemoryArtifactService
from google.adk.sessions import InMemorySessionService, Session
from google.genai import types
from dotenv import load_dotenv
load_dotenv(override=True)
async def main():
app_name = 'Arcade Google ADK'
user_id = '{arcade_user_id}'
session_service = InMemorySessionService()
artifact_service = InMemoryArtifactService()
# This creates a simple agent, and for now it does not have any tools.
agent = Agent(
model="gemini-2.0-flash",
name="simple_agent",
instruction="You are a helpful assistant that can help users with"
" everyday tasks.",
)
session = await session_service.create_session(
app_name=app_name, user_id=user_id, state={
"user_id": user_id,
}
)
runner = Runner(
app_name=app_name,
agent=agent,
artifact_service=artifact_service,
session_service=session_service,
)
# This is a helper function to run the agent with a prompt.
async def run_prompt(session: Session, new_message: str):
content = types.Content(
role='user', parts=[types.Part.from_text(text=new_message)]
)
async for event in runner.run_async(
user_id=user_id,
session_id=session.id,
new_message=content,
):
if event.content.parts and event.content.parts[0].text:
print(f'** {event.author}: {event.content.parts[0].text}')
# This is the main agent loop to prompt the user until they exit.
while True:
user_input = input("User: ")
if user_input.lower() == "exit":
print("Goodbye!")
break
await run_prompt(session, user_input)
if __name__ == "__main__":
asyncio.run(main())So far, we’ve only used Google ADK’s primitives. The agent is already functional and will invoke the model and keep the messages in memory for the duration of the conversation.
Now, let’s add a tool to the agent.
Add a tool to the agent
Now, let’s update the code to add:
- An Arcade client
- Get a specific tool from the Arcade Platform
- Pass the tool to the agent
In 5 lines of code, we’ve done all of this. And now the agent can invoke the tool. If the tool requires authorization, the tool will reply with a URL for the user to visit, which will be displayed to the user. If the tool does not require authorization, the tool will be invoked directly.
import asyncio
from arcadepy import AsyncArcade
from google.adk import Agent, Runner
from google.adk.artifacts import InMemoryArtifactService
from google.adk.sessions import InMemorySessionService, Session
from google.genai import types
from google_adk_arcade.tools import get_arcade_tools
from dotenv import load_dotenv
load_dotenv(override=True)
async def main():
# initialize the Arcade client
client = AsyncArcade()
app_name = "Arcade Google ADK"
user_id = "mateo@arcade.dev"
session_service = InMemorySessionService()
artifact_service = InMemoryArtifactService()
# This function returns a list of tools in the format expected by ADK
gmail_list_emails = await get_arcade_tools(client, tools=["Gmail_ListEmails"])
# We've updated the agent to access a single tool
agent = Agent(
model="gemini-2.0-flash",
name="simple_agent",
instruction="You are a helpful assistant that can help users with"
" everyday tasks. It is very important that you use"
" the provided tools to ensure the task is successfully"
" achieved",
tools=gmail_list_emails, # pass the tool to the agent
)
session = await session_service.create_session(
app_name=app_name, user_id=user_id, state={
"user_id": user_id,
}
)
runner = Runner(
app_name=app_name,
agent=agent,
artifact_service=artifact_service,
session_service=session_service,
)
# This is a helper function to run the agent with a prompt.
async def run_prompt(session: Session, new_message: str):
content = types.Content(
role='user', parts=[types.Part.from_text(text=new_message)]
)
async for event in runner.run_async(
user_id=user_id,
session_id=session.id,
new_message=content,
):
if event.content.parts and event.content.parts[0].text:
print(f'** {event.author}: {event.content.parts[0].text}')
# This is the main agent loop to prompt the user until they exit.
while True:
user_input = input("User: ")
if user_input.lower() == "exit":
print("Goodbye!")
break
await run_prompt(session, user_input)
if __name__ == "__main__":
asyncio.run(main())