1. Introduction
In this codelab, you will learn how to build a pro-code AI agent using the Agent Development Kit (ADK) that connects directly to the official Google Workspace MCP servers.
Model Context Protocol (MCP) is an open standard that enables AI models to securely use tools provided by remote servers. ADK is Google's pro-code framework for building autonomous agents. By combining them, you can create highly customized agents grounded in your Gmail, Google Drive, Google Calendar, Google Chat, and People data.
For complete documentation on available tools and configuration, see Configure Google Workspace MCP servers.
What you'll do
- Enable Google Workspace MCP services in your Google Cloud project.
- Configure OAuth consent and create credentials for both local testing and production deployment.
- Build a local ADK agent that connects to the 5 Workspace MCP servers using static tokens.
- Build and deploy a production-ready ADK agent to Gemini Enterprise Agent Platform (GEAP) Agent Runtime that uses dynamic token injection.
- Register and test your custom agent natively within Gemini Enterprise.
What you'll need
- A web browser (e.g., Chrome).
- A Google Cloud project with billing enabled.
- A Google Workspace account (with smart features turned on).
- Python 3.11+ installed on your local machine.
- Google Cloud CLI (
gcloud) installed and initialized.
2. Before you begin
Create or Select a Google Cloud project
Console Option
In the Google Cloud Console, select or create a Google Cloud project.
CLI Option
Create a new project and set it as active:
gcloud projects create YOUR_PROJECT_ID
gcloud config set project YOUR_PROJECT_ID
Enable the APIs
To use the Google Workspace MCP servers, you must enable both the standard Google Workspace APIs and the dedicated MCP services.
Console Option
Click the following buttons to enable them using the web browser:
CLI Option Execute these terminal commands:
# Enable standard GWS APIs
gcloud services enable chat.googleapis.com \
drive.googleapis.com \
calendar-json.googleapis.com \
people.googleapis.com \
gmail.googleapis.com
# Enable dedicated MCP services
gcloud services enable calendarmcp.googleapis.com \
chatmcp.googleapis.com \
drivemcp.googleapis.com \
gmailmcp.googleapis.com
Configure the Chat App
To use the Google Chat MCP server, you must configure a Chat app in your Google Cloud project.
- Go to Google Chat API > Manage > Configuration.
- Set up the Chat app:
- App name:
ADK Workspace Agent - Avatar URL:
https://developers.google.com/chat/images/quickstart-app-avatar.png - Description:
MCP server connection for ADK Agent - Under Functionality, turn off Enable interactive features.
- Under Logs, select Log errors to Logging.
- App name:
- Click Save.
3. Configure OAuth Consent and Clients
The Google Workspace MCP servers use OAuth 2.0 for secure authentication. You must configure the OAuth consent screen and create two separate client IDs: one for local development and one for the deployed agent.
Set up the OAuth Consent Screen
- In the Google Cloud console, click the Navigation menu (hamburger icon) in the top-left corner. Select Google Auth Platform > Branding (or APIs & Services > OAuth consent screen if Google Auth Platform is not visible).
- Configure App Information:
- App name:
Workspace ADK Agent - User support email: Select your email.
- App name:
- Configure Audience: Select Internal.
- Configure Contact Information: Enter your email address, then click Create.
- Go to Data Access > Add or Remove Scopes. Under Manually add scopes, add the following scopes to grant access to all 5 services:
https://www.googleapis.com/auth/calendar.calendarlist.readonly https://www.googleapis.com/auth/calendar.events https://www.googleapis.com/auth/calendar.calendars https://www.googleapis.com/auth/chat.spaces https://www.googleapis.com/auth/chat.messages https://www.googleapis.com/auth/drive.readonly https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/gmail.readonly https://www.googleapis.com/auth/gmail.compose https://www.googleapis.com/auth/gmail.send https://www.googleapis.com/auth/directory.readonly https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/contacts.readonly https://www.googleapis.com/auth/cloud-platform - Click Add to Table, then Update, and finally Save.
Create Client ID for Local Development (Desktop App)
- In the Google Cloud console, navigate to Google Auth Platform > Clients (or APIs & Services > Credentials). Click Create Credentials (or Create Client) and select OAuth client ID.
- Select Desktop app as the application type.
- Name it
Workspace Agent Local. - Click Create and download the JSON file. Save it locally as
client_secret.json.
4. Agent Development and Testing
This section describes how to build the agent environment. We will use a static token approach for testing, where we fetch an OAuth token using gcloud and pass it to ADK's McpToolset. You can follow these steps using either your Local Machine or Google Cloud Shell.
Choose your environment: Local Machine or Google Cloud Shell to set up your development environment. Both methods will use a shared Python script for authentication to ensure consistency across platforms.
1. Set Up Environment Directory
Execute the following commands in your terminal to create a project directory and install the required packages.
- For Google Cloud Shell: First, click the Activate Cloud Shell icon (
>_) in the top right toolbar of the Google Cloud Console. - For Local Machine: Open your standard terminal.
mkdir -p gws-adk-agent/workspace_agent
cd gws-adk-agent
python3 -m venv .venv
source .venv/bin/activate
pip install google-adk poetry google-auth-oauthlib
2. Prepare Credentials File
You must place the client_secret.json file you downloaded in the previous step into the root of your gws-adk-agent directory.
- Local Machine: Move or copy the downloaded
client_secret.jsonfile into thegws-adk-agentdirectory. - Google Cloud Shell: Create the file by running the following command in Cloud Shell (replace
[PASTE_JSON_HERE]with your actual JSON content):
cat << 'EOF' > client_secret.json
[PASTE_JSON_HERE]
EOF
3. Authenticate and Generate .env (auth.py)
To handle authentication consistently and avoid environment-specific CLI routing issues, we use a custom Python script powered by the official Google authentication libraries. This script manages the OAuth flow, saves Application Default Credentials (ADC) locally, and generates the required .env file.
Create a file named auth.py in the gws-adk-agent directory and add the following code:
import json
import os
from urllib.parse import urlparse, parse_qs
import google.auth
from google_auth_oauthlib.flow import InstalledAppFlow
CLIENT_SECRET_FILE = 'client_secret.json'
SCOPES = [
"https://www.googleapis.com/auth/cloud-platform",
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/chat.spaces.readonly",
"https://www.googleapis.com/auth/chat.messages",
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/gmail.readonly",
"https://www.googleapis.com/auth/gmail.compose",
"https://www.googleapis.com/auth/directory.readonly",
"https://www.googleapis.com/auth/contacts.readonly"
]
# Initialize the flow from the client secrets JSON
flow = InstalledAppFlow.from_client_secrets_file(
CLIENT_SECRET_FILE,
scopes=SCOPES,
redirect_uri='http://localhost:8085/'
)
# Generate the Auth URL
auth_url, expected_state = flow.authorization_url(prompt='consent', access_type='offline')
print("\n=== GOOGLE OAUTH OFFICIAL LIBRARY FLOW ===")
print("1. Copy the following link and paste it into your browser (or click it if supported):\n")
print(auth_url)
print("\n2. Authorize the application.")
print("3. Your browser will redirect to a 'localhost' page (it will show a 'Site can't be reached' error, which is EXPECTED and normal).")
print("4. Copy the ENTIRE URL from your browser's address bar (including the http://localhost:8085/ part).\n")
# Get the redirected URL from the user
redirected_url = input("Paste the full localhost URL here: ").strip()
# Exchange the redirect URL for tokens
print("\nExchanging code for tokens...")
try:
parsed_url = urlparse(redirected_url)
query_params = parse_qs(parsed_url.query)
returned_state = query_params.get('state', [None])[0]
code = query_params.get('code', [None])[0]
if not code:
raise ValueError("No 'code' parameter found in the URL.")
if returned_state != expected_state:
raise ValueError("CSRF Warning! State mismatch.")
flow.fetch_token(code=code)
creds = flow.credentials
except Exception as e:
print(f"Authentication failed: {e}")
exit(1)
if not creds.refresh_token:
print("\nError: No refresh token returned. You may need to revoke access and try again.")
exit(1)
# Save Application Default Credentials
adc_data = {
"client_id": creds.client_id,
"client_secret": creds.client_secret,
"refresh_token": creds.refresh_token,
"type": "authorized_user"
}
adc_dir = os.path.expanduser("~/.config/gcloud")
os.makedirs(adc_dir, exist_ok=True)
adc_path = os.path.join(adc_dir, "application_default_credentials.json")
with open(adc_path, "w") as f:
json.dump(adc_data, f, indent=2)
# Detect Project ID
try:
_, project_id = google.auth.default()
except Exception:
project_id = None
project_id = project_id or os.environ.get("GOOGLE_CLOUD_PROJECT", "YOUR_PROJECT_ID")
# Save to .env for local development (relative to project root)
env_dir = "workspace_agent"
os.makedirs(env_dir, exist_ok=True)
env_path = os.path.join(env_dir, ".env")
with open(env_path, "w") as f:
f.write("GOOGLE_GENAI_USE_VERTEXAI=1\n")
f.write(f"GOOGLE_CLOUD_PROJECT={project_id}\n")
f.write("GOOGLE_CLOUD_LOCATION=us-central1\n")
print(f"\nSuccess! Application Default Credentials saved to: {adc_path}")
print(f"Environment variables saved to: {env_path}")
if project_id == "YOUR_PROJECT_ID":
print("NOTE: Could not automatically detect Project ID. Please update it manually in .env")
Run the script in your terminal:
python3 auth.py
Create the Agent Code
Regardless of the environment you chose in the preceding step, the agent code remains exactly the same. Create a file named agent.py inside your pre-created workspace_agent subdirectory and add the following code. This script uses Application Default Credentials (ADC) to provide authorization, automatically validating and refreshing credentials purely in memory via a dynamic header provider.
import datetime
import google.auth
from google.auth.transport.requests import Request
from google.adk.agents.llm_agent import LlmAgent
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
MODEL = "gemini-2.5-flash"
# Load credentials from Application Default Credentials (ADC) saved by auth.py
creds, _ = google.auth.default()
# 1. STARTUP SAFETY: Ensure valid token at import time for static tool discovery (e.g. adk web UI load)
if not creds.valid:
creds.refresh(Request())
print("\n[Agent Startup] Access token refreshed from ADC.")
def auth_header_provider(tool_context=None) -> dict[str, str]:
"""2. RUNTIME SAFETY: Dynamically provides auth headers, refreshing if expired during the session."""
if not creds.valid:
creds.refresh(Request())
print("\n[Agent Runtime] Access token refreshed from ADC.")
return {"Authorization": f"Bearer {creds.token}"}
# Initialize the 5 GWS MCP servers with combined startup headers and dynamic runtime provider
calendar_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://calendarmcp.googleapis.com/mcp/v1",
headers={"Authorization": f"Bearer {creds.token}"}
),
header_provider=auth_header_provider
)
chat_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://chatmcp.googleapis.com/mcp/v1",
headers={"Authorization": f"Bearer {creds.token}"}
),
header_provider=auth_header_provider
)
drive_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://drivemcp.googleapis.com/mcp/v1",
headers={"Authorization": f"Bearer {creds.token}"}
),
header_provider=auth_header_provider
)
gmail_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://gmailmcp.googleapis.com/mcp/v1",
headers={"Authorization": f"Bearer {creds.token}"}
),
header_provider=auth_header_provider
)
people_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://people.googleapis.com/mcp/v1",
headers={"Authorization": f"Bearer {creds.token}"}
),
header_provider=auth_header_provider
)
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
# Define the agent and attach all 5 toolsets
root_agent = LlmAgent(
model=MODEL,
name='gws_adk_agent',
instruction=f"""You are a helpful assistant grounded in the user's Google Workspace data.
Today's current date is {current_date}. Always calculate relative dates (like 'this week' or 'upcoming meetings') using this reference.
Use the provided MCP tools to answer questions about their Calendar, Chat, Drive, Gmail, and Contacts.""",
tools=[calendar_mcp, chat_mcp, drive_mcp, gmail_mcp, people_mcp]
)
Run and Test Your Agent
You can interact with your agent using either the interactive Web UI or directly inside your Terminal/Shell.
Option 1: Interactive Web UI
If you are on a Local Machine:
- From your
gws-adk-agentproject root directory, start the ADK web interface:adk web - Open
http://localhost:8000in your browser to chat with your agent.
If you are in Google Cloud Shell:
- From your
gws-adk-agentproject root directory, start the ADK web interface explicitly enforcing port 8080:adk web --port 8080 --allow_origins=* - Click the Web Preview button in the top right of the Cloud Shell toolbar and select Preview on port 8080 to open the interface in a new tab.
Option 2: Terminal CLI Mode (Alternative)
If you prefer to stay in the terminal or want to avoid setting up web browser previews, ADK provides a native interactive REPL chat mode.
From your gws-adk-agent project root directory, execute the following command (this works identically on both a Local Machine and Google Cloud Shell):
adk run workspace_agent
You will enter an interactive chat session directly in your shell:
Running agent gws_adk_agent, type exit to exit.
[user]:
Try Prompting Your Agent
Regardless of the interface you chose, try testing the agent with queries that leverage the Workspace MCP tools:
What are my upcoming meetings this week?Summarize the last 3 unread emails in my Gmail.
5. Production Deployment
To deploy the agent to production, we cannot use a hardcoded local token. Instead, we use ADK's header_provider to dynamically extract the OAuth access token injected by the Gemini Enterprise platform when a user interacts with the agent.
Create the Production Agent Code
Create a directory package named enterprise_ai and create an agent.py file inside it:
mkdir -p enterprise_ai
Write the following content to enterprise_ai/agent.py:
import datetime
import os
import re
from google.adk.agents.llm_agent import LlmAgent
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
from google.adk.tools.tool_context import ToolContext
MODEL = "gemini-2.5-flash"
# This name MUST match the Authorization Name used during Gemini Enterprise registration
CLIENT_AUTH_NAME = "workspace-adk-auth"
def _get_access_token_from_context(tool_context: ToolContext) -> str:
"""Dynamically parses the user bearer token injected into the ToolContext state."""
escaped_name = re.escape(CLIENT_AUTH_NAME)
pattern = re.compile(fr"^{escaped_name}_\d+$")
state_dict = tool_context.state.to_dict() if hasattr(tool_context.state, 'to_dict') else tool_context.state
matching_keys = [k for k in state_dict.keys() if pattern.match(k)]
if matching_keys:
return state_dict.get(matching_keys[0])
raise Exception(f"No bearer token found in ToolContext state matching pattern {pattern.pattern}")
def auth_header_provider(tool_context: ToolContext) -> dict[str, str]:
"""Provides the dynamic Authorization header for MCP requests."""
token = _get_access_token_from_context(tool_context)
return {"Authorization": f"Bearer {token}"}
# Initialize toolsets using the dynamic header_provider
calendar_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(url="https://calendarmcp.googleapis.com/mcp/v1"),
header_provider=auth_header_provider
)
chat_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(url="https://chatmcp.googleapis.com/mcp/v1"),
header_provider=auth_header_provider
)
drive_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(url="https://drivemcp.googleapis.com/mcp/v1"),
header_provider=auth_header_provider
)
gmail_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(url="https://gmailmcp.googleapis.com/mcp/v1"),
header_provider=auth_header_provider
)
people_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(url="https://people.googleapis.com/mcp/v1"),
header_provider=auth_header_provider
)
current_date = datetime.datetime.now().strftime("%Y-%m-%d")
root_agent = LlmAgent(
model=MODEL,
name='enterprise_ai',
instruction=f"""You are an enterprise assistant grounded securely in the user's Workspace data.
Today's current date is {current_date}. Always calculate relative dates (like 'this week' or 'upcoming meetings') using this reference.
Always use the provided MCP tools to fetch context from Calendar, Chat, Drive, Gmail, and People.""",
tools=[calendar_mcp, chat_mcp, drive_mcp, gmail_mcp, people_mcp]
)
Deploy to GEAP Agent Runtime
Deploy your pro-code agent using the ADK CLI:
adk deploy agent_engine \
--project=$(gcloud config get-value project) \
--region=us-central1 \
--display_name="Workspace ADK Agent" \
enterprise_ai
Wait for the deployment to finish and copy the generated Reasoning Engine resource name from the terminal output (e.g., projects/PROJECT_ID/locations/us-central1/reasoningEngines/ENGINE_ID).
6. Register in Gemini Enterprise
Now, we bring the custom ADK agent into Gemini Enterprise so users can chat with it natively.
Create Client ID for Production (Web Application)
To deploy your agent to production, you must create a Web application client ID. Unlike the desktop client used for local testing, a web application client enables a secure, server-side OAuth flow. This allows the hosted agent on GEAP Agent Runtime to securely receive the user's authentication tokens forwarded by Gemini Enterprise, using the specified redirect URI. This setup is necessary for the agent to securely access Google Workspace data on behalf of the user in a production environment.
- In the Google Cloud console, click the Navigation menu (hamburger icon) in the top-left corner. Select Google Auth Platform > Clients (or APIs & Services > Credentials if Google Auth Platform is not visible). Click Create Credentials (or Create Client) and select OAuth client ID.
- Select Web application as the application type.
- Name it
Workspace Agent Production. - In the Authorized redirect URIs section, add the following URIs:
- Click Add URI and enter
https://vertexaisearch.cloud.google.com/oauth-redirect. - Click Add URI again and enter
https://vertexaisearch.cloud.google.com/static/oauth/oauth.html.
- Click Add URI and enter
- Click Create. In the "OAuth client created" pop-up (or from the Clients list), copy the Client ID and Client Secret. You will need these when registering the agent in Gemini Enterprise.
Create a Gemini Enterprise App
- In the Google Cloud console, go to the Gemini Enterprise page:
- Under the Gemini Enterprise card, click Manage.
- Click Create app.
- In the Gemini Enterprise section, click Create.
- In the Your app name field, enter a name for your app. Your app ID appears under the app name.
- In the External name of your company or organization field, enter the company or organization name. For this tutorial, you can use
Cymbal Bank. - Select global (Global) as the location for your app.
- Click Continue.
Register the Custom Agent
- Open the Gemini Enterprise console:
- Select your active app, navigate to Agents, and click + Add agent > Add Custom agent via Agent Runtime.
- In the Authorizations section, click Add authorization:
- Authorization name:
workspace-adk-auth(Must exactly match CLIENT_AUTH_NAME in your Python code) - Client ID: Paste the Production Web Application Client ID created above.
- Client secret: Paste the Production Web Application Client Secret created above.
- Token URI:
https://oauth2.googleapis.com/token - Authorization URI: Construct the URI by replacing
YOUR_CLIENT_IDwith the Client ID you copied in step 5 above:https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID&redirect_uri=https%3A%2F%2Fvertexaisearch.cloud.google.com%2Fstatic%2Foauth%2Foauth.html&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.calendars%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcalendar.events%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fcloud-platform%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.send%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fgmail.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fchat.spaces%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fchat.messages%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdirectory.readonly&include_granted_scopes=true&response_type=code&access_type=offline&prompt=consent
- Authorization name:
- Click Done, then click Next.
- In the Configuration section:
- Agent name:
Workspace Pro Agent - Description:
Use this agent to answer questions about your Google Workspace data, including Gmail, Google Drive, Google Calendar, Google Chat, and Contacts. It can find files, summarize emails, check your schedule, and look up contact information. - Agent Runtime reasoning engine: Paste the engine resource name you copied from the
adk deployoutput.
- Agent name:
- Click Create.
Try the Agent in Gemini Enterprise
You can interact with your agent either using the Google Cloud Console Preview (fastest for developers) or the Gemini Enterprise Web App (end-user experience).
Option 1: Google Cloud Console Preview
- In the Google Cloud console, go to the Gemini Enterprise page:
- In the navigation menu, click Apps and select the app you just created.
- Click Preview or click Open preview on the top right.
- In the search bar, enter the following query:
Search for files in Drive related to 'Project Milestone', summarize them, and tell me if I have any meetings with the project owner today. - Press Enter to submit the query and view the results directly in the console.
Option 2: Gemini Enterprise Web App
- Open your Gemini Enterprise Web App interface.
- Go to Menu ☰ > Agents and select Workspace Pro Agent under From your organization.
- Type the same query as in the Google Cloud Console Preview option.
- Click Authorize when prompted to go through the OAuth user consent flow.
- The agent will execute tasks seamlessly across multiple services using the MCP protocol!
7. Clean up
To avoid unnecessary charges, clean up your resources:
Console Option
Go to the API & Services Dashboard, select the MCP services you enabled (e.g., Calendar MCP, Gmail MCP), and click Disable API. Delete the OAuth Client IDs under Google Auth Platform > Clients, and delete the Reasoning Engine deployment from the Gemini Enterprise Console.
CLI Option
Execute the following terminal commands to disable the MCP services:
# Disable Workspace MCP services
gcloud services disable calendarmcp.googleapis.com \
chatmcp.googleapis.com \
drivemcp.googleapis.com \
gmailmcp.googleapis.com
8. Congratulations
Congratulations! You have successfully built, tested, and deployed a pro-code ADK AI agent connected directly to the official Google Workspace MCP servers.
What you've learned
- How to enable Google Workspace MCP services in Google Cloud.
- How to handle OAuth credentials for local ADK testing using static headers.
- How to implement dynamic token injection using
header_providerfor production agents. - How to deploy an ADK agent to GEAP Agent Runtime and register it in Gemini Enterprise.