GCP – Tools Make an Agent: From Zero to Assistant with ADK
Imagine that you’re a project manager at QuantumRoast, a global coffee machine company.
You help your teammates navigate a sea of engineering roadmaps, sudden strategy pivots (we’re doing matcha now!), and incoming tickets from customers— everything from buggy invoice systems to a coffee machine that’s making a high-pitched noise 24/7.
On a regular day, you have about fifty open browser tabs: the internal ticket system, email, chat, GitHub, Google Search, StackOverflow, and more. You like your job and your teammates— but some days, you get overwhelmed.
What if there was a helper we could build to help you create and triage software tickets, and debug issues? An AI agent makes this possible.
Tools 101
What makes AI agents unique from other software systems? In the post “AI Agents in a Nutshell,” we discussed how AI agents use models, not just hardcoded logic, to reason their way through a problem. But more than just LLM-based reasoning, AI agents are uniquely powered to gather external data and then take action on behalf of the user. Rather than telling you how to solve a problem, an AI agent can help you actually solve it. How do we do this? With tools!
A tool is a capability that helps an AI agent interact with the world. A tool can be almost anything: an inline function, a hosted database, a third-party API, or even another agent. AI Agent frameworks like Agent Development Kit (ADK) have built-in support for tools, supporting a variety of tool types that we’ll cover in just a moment.
But how does an agent know not only when to call a certain tool, but also how to call it? The agent’s model plays a few key roles here.
The first is tool selection. We provide our agent with a list of tools and some instructions for how to use them. When a user prompts the agent, the agent’s model helps decide which tools to call, and why, in order to help the user.
The second key step is function-calling. Function calling is a bit of a misnomer because the model is not actually calling the tool, but rather, preparing to call it by formatting the request body that the framework then uses to call the tool.
Lastly, the model helps interpret the response from that tool — say, a list of open bugs from the database— and decides whether to take further action, or respond to the user with that information.
To see all this in action, let’s build the QuantumRoast bug assistant agent using ADK Python.
Function Tool
The simplest ADK tool is the function tool. This is an inline function that can perform a calculation or algorithm. For instance, we can write a function tool to get today’s date:
- code_block
- <ListValue: [StructValue([(‘code’, ‘def get_current_date() -> dict:rn “””rn Get the current date in the format YYYY-MM-DDrn “””rn return {“current_date”: datetime.now().strftime(“%Y-%m-%d”)}’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb972a90>)])]>
This way, if the user asks about bugs filed “in the last week,” the model understands what specific dates it should be adding to the request body when it calls our IT Ticket database. Here’s what that looks like in action:
Built-in Tool
Another type of ADK tool is a built-in tool. These are tools that work with Google’s flagship model features, like code execution inside the model itself. For instance, can attach the Google Search built-in tool to our bug assistant agent, to allow the agent to do basic web-searches in order to gather more information about a bug:
- code_block
- <ListValue: [StructValue([(‘code’, ‘from google.adk.tools import google_searchrnfrom google.adk.tools.agent_tool import AgentToolrnrnsearch_agent = Agent(rn model=”gemini-2.5-flash”,rn name=”search_agent”,rn instruction=”””rn You’re a specialist in Google Search.rn “””,rn tools=[google_search],rn)rnsearch_tool = AgentTool(search_agent)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb972a30>)])]>
Here, we’re actually wrapping that Google Search tool in its own agent with its own system instructions, effectively using an agent as a tool.
Third-party API Tool
To plug our bug agent into StackOverflow’s powerful Q&A data, we can pull from LangChain’s extensive tools library— specifically, the StackExchange API Wrapper tool. ADK supports third-party tools via LangChain, so adding this tool to our ADK agent requires just two lines of code.
- code_block
- <ListValue: [StructValue([(‘code’, ‘from google.adk.tools.langchain_tool import LangchainToolrnfrom langchain_community.tools import StackExchangeToolrnfrom langchain_community.utilities import StackExchangeAPIWrapperrnrnstack_exchange_tool = StackExchangeTool(api_wrapper=StackExchangeAPIWrapper())rnlangchain_tool = LangchainTool(stack_exchange_tool)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb858b20>)])]>
Pulling in third-party API tools is great for re-using existing tools. But imagine that you’ve got a bunch of your own internal APIs and third-party APIs you want to integrate your agent with— GitHub, for example. In a standard software application, you’d have to write your own code to call GitHub’s APIs. But GitHub’s API is big! If every agent developer working with GitHub had to implement their own GitHub tools, that’s a lot of duplicated effort.
This is where a protocol called MCP comes in…
MCP Tool (API)
MCP stands for Model Context Protocol. It’s an open tool protocol introduced by Anthropic in 2024. MCP provides an abstraction layer between your AI agent and tool “backends” (APIs, databases).
MCP has some unique specifications. Unlike standard HTTP, MCP provides a stateful, two-way connection between the client and server. It has its own way of defining tools and tool-specific error messages. A tool provider can then build MCP Servers on top of their APIs, exposing one or more pre-built tools for developers and users. Then, agent frameworks can initialize MCP Clients inside an agent application, to discover and call those tools.
This is exactly what GitHub did in 2025. They created a remote MCP server to allow different types of AI applications— from AI coding assistants, to custom agents— to easily call GitHub’s APIs. The GitHub MCP server exposes different parts of GitHub’s functionality, from issue and pull requests, to notifications and code security. Here, we use ADK’s MCPToolset
to call the GitHub remote MCP server:
For our bug assistant, we will expose just some read-only GitHub tools, to allow QuantumRoast employees to find issues related to open-source dependencies, to see if that can help root-cause bugs they’re seeing in the internal ticket system. We’ll use ADK’s MCPToolset
with a tool_filter
to set this up. The tool-filter
exposes only the GitHub tools we need, which not only hides the tools we don’t want users accessing (think: sensitive repo actions), but also protects the agent’s model from getting overwhelmed when trying to choose the right tool for the job.
- code_block
- <ListValue: [StructValue([(‘code’, ‘from google.adk.tools.mcp_tool import MCPToolset, StreamableHTTPConnectionParamsrnrnmcp_tools = MCPToolset(rn connection_params=StreamableHTTPConnectionParams(rn url=”https://api.githubcopilot.com/mcp/”,rn headers={rn “Authorization”: “Bearer ” + os.getenv(“GITHUB_PERSONAL_ACCESS_TOKEN”),rn },rn ),rn # Read only toolsrn tool_filter=[rn “search_repositories”,rn “search_issues”,rn “list_issues”,rn “get_issue”,rn “list_pull_requests”,rn “get_pull_request”,rn ],rn)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb858640>)])]>
Note how we also need to provide a GitHub Personal Access Token (PAT) to our MCPToolset
definition, just like how you’d provide an auth token when setting up a standard API client in your code. This PAT is scoped to only access public repository data, with no scopes around sensitive user or repository actions.
Now, we have a set of GitHub MCP tools that our agent can call. For instance, let’s say that one of QuantumRoast’s services relies on XZ utils, a data compression tool. Our internal bug ticket system is tracking a CVE (security vulnerability) from last year, which we can trace back to the XZ Utils GitHub repo using the StackOverflow and Google Search tools. We can then use one of GitHub’s MCP tools, search_issues
, to determine when and how that CVE was patched:
MCP Tool (Database)
The last tool to cover is QuantumRoast’s internal bug ticket database. This is a PostgreSQL database running on Google Cloud SQL. We have a table with bugs, each with a ticket_id
, title
, description
, assignee
, and other fields.
We could write our own Python code using an ORM like sqlalchemy to call our SQL database (eg. get ticket by ID
). Then we could wrap that code in a Function Tool, just like we did for get_current_date()
. But this could add toil — more lines of code, plus we’d have to write the database connection logic and handle auth on our own.
Instead, we are going to use MCP, much like we used it for the GitHub API. We will use a prebuilt MCP server again — but this time, the tool “backend” will be our own database. We’ll pull in the MCP Toolbox for Databases, a Google-built, open-source MCP server that provides connectors and production-grade features like auth, for a variety of data sources, from BigQuery to Redis.
To wire up the MCP toolbox to Cloud SQL, we’ll create a tools.yaml
configuration file that tells the Toolbox MCP server where our database lives, and the tools we want to create for it. For example, we could transform our bug description
column into searchable vector embeddings, to enable a fuzzy search-tickets
tool within our agent:
- code_block
- <ListValue: [StructValue([(‘code’, “sources:rn postgresql: rn kind: cloud-sql-postgresrn project: my-gcp-projectrn region: us-central1rn instance: software-assistantrn database: tickets-dbrn user: postgresrn password: ${POSTGRES_PASSWORD}rntools:rn search-tickets:rn kind: postgres-sqlrn source: postgresqlrn description: Search for similar tickets based on their descriptions.rn parameters:rn – name: queryrn type: stringrn description: The query to perform vector search with.rn statement: |rn SELECT ticket_id, title, description, assignee, priority, status, (embedding <=> embedding(‘text-embedding-005’, $1)::vector) as distancern FROM ticketsrn ORDER BY distance ASCrn LIMIT 3;rn…”), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb858340>)])]>
We can define several other tools, like create-new-ticket
and update-ticket-status
, in that tools.yaml
file. From there, we can run the Toolbox MCP server locally:
- code_block
- <ListValue: [StructValue([(‘code’, ‘➜ mcp-toolbox git:(software-bug-github) ✗ ./toolbox –tools-file=”tools.yaml”rnrn2025-06-17T11:07:23.963075-04:00 INFO “Initialized 1 sources.”rn2025-06-17T11:07:23.963214-04:00 INFO “Initialized 0 authServices.”rn2025-06-17T11:07:23.963281-04:00 INFO “Initialized 9 tools.”rn2025-06-17T11:07:23.963341-04:00 INFO “Initialized 2 toolsets.”rn2025-06-17T11:07:23.963704-04:00 INFO “Server ready to serve!”‘), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb858b50>)])]>
Then finally, we can plug our bug assistant agent into that MCP Toolbox server:
- code_block
- <ListValue: [StructValue([(‘code’, ‘from toolbox_core import ToolboxSyncClientrnrnTOOLBOX_URL = os.getenv(“MCP_TOOLBOX_URL”, “http://127.0.0.1:5000”)rntoolbox = ToolboxSyncClient(TOOLBOX_URL)rntoolbox_tools = toolbox.load_toolset(“tickets_toolset”)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb8586d0>)])]>
From there, our agent has access to all those SQL database tools to create and triage bugs in the QuantumRoast ticket database:
Putting it all together
We just toured five different ADK tool types, from simple FunctionTools
, to third-party LangChain tools, to powerful MCP tools.
Now, we can build a QuantumRoast bug assistant agent to help that busy project manager navigate their day-to-day work.
To do this, we’ll create a single LLMAgent using ADK Python, powered by Gemini 2.5 Flash (reasoning model):
- code_block
- <ListValue: [StructValue([(‘code’, ‘root_agent = Agent(rn model=”gemini-2.5-flash”,rn name=”software_bug_assistant”,rn instruction=agent_instruction,rn tools=[get_current_date, search_tool, langchain_tool, *toolbox_tools, mcp_tools],rn)’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb8587c0>)])]>
We equip our root_agent
with instructions. We outline the desired process that we want the agent to go through:
- code_block
- <ListValue: [StructValue([(‘code’, ‘agent_instruction = “””rnYou are a skilled expert in triaging and debugging software issues for a coffee machine company, QuantumRoast.rn…rnYour general process is as follows:rn1. **Understand the user’s request.** Analyze the user’s initial request to understand the goal – for example, “I am seeing X issue. Can you help me find similar open issues?” If you do not understand the request, ask for more information. rn2. **Identify the appropriate tools.** You will be provided with tools for a SQL-based bug ticket database (create, update, search tickets by description). You will also be able to web search via Google Search. Identify one **or more** appropriate tools to accomplish the user’s request. rn…’), (‘language’, ‘lang-py’), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb858e50>)])]>
Inside our system instructions, we also provide details and context on all our tools. This helps the model understand when to invoke which tool.
- code_block
- <ListValue: [StructValue([(‘code’, ‘**TOOLS:**rnrn1. **get_current_date:**rn This tool allows you to figure out the current date (today). If a userrn asks something along the lines of “What tickets were opened in the lastrn week?” you can use today’s date to figure out the past week.rnrn2. **search-tickets**rn This tool allows you to search for similar or duplicate tickets byrn performing a vector search based on ticket descriptions. A cosine distancern less than or equal to 0.3 can signal a similar or duplicate ticket.rn…’), (‘language’, ”), (‘caption’, <wagtail.rich_text.RichText object at 0x3e16fb858040>)])]>
Now that our agent code is ready to go, we can deploy this whole setup to Google Cloud, running the agent and MCP toolbox server on Cloud Run, the bug ticket database in Cloud SQL, with Gemini 2.5 Flash on Vertex AI. Check out the deployment instructions here.
Get started with agent tools
To sum up, tools “make an agent.” They’re the difference between an AI that can tell you what to do, and one that can help you actually do it.
If you’re new to AI agents and tools, start small. Write a basic ADK agent using an inline function. Then, consider pulling in an OpenAPI Tool for your API, or a Third-party LangChain tool like YouTube. Then, wade into the world of MCP by first using an off-the-shelf MCP server like the MCP Toolbox for Databases. Then, consider building your own MCP server for your own tool backend.
To get started today, check out these links, and thanks for reading!
Read More for the details.