Lab 27: Using a Stateful File System Tool Challenge
Goal
In this lab, you will learn how to connect your ADK agent to an external, stateful tool using the Model Context Protocol (MCP). You will use the McpToolset to connect to a pre-built, open-source MCP server that provides file system operations. This will allow your agent to list files and read their contents from your local machine.
Prerequisites
- Node.js and npx: The MCP server we will use is a Node.js package. If you don't have it, install Node.js (which includes npx) from the official website.
Step 1: Create the Agent Project
-
Navigate to your training directory:
cd /path/to/your/adk-training -
Create the agent project:
uv run adk create mcp_agent
cd mcp_agent -
Install the MCP extra.
mcpis not part of ADK's base install — it only comes in via ADK's[mcp]extra, which pins a compatible version:uv add "google-adk[mcp]"
Step 2: Create a Test Directory and File
The MCP file system server needs a directory to operate on. Let's create one.
-
Create a directory for the tool to access: Inside your
mcp_agentproject, create a directory namedtest_files.mkdir test_files -
Create a sample file: Inside
test_files, create a file namedhello.txt.echo "Hello from the MCP world!" > test_files/hello.txt
Step 3: Configure the Agent to Use the MCP Toolset
Because the McpToolset requires Python code to configure the connection, we must define our agent in an agent.py file.
-
Create the
agent.pyfile: In themcp_agentdirectory, create a file namedagent.py. -
Create the
__init__.pyfile: This empty file is crucial. It tells Python to treat themcp_agentdirectory as a package, allowinguv run adk webto discover and load youragent.py.touch __init__.py -
Complete the
agent.pyscript: Exercise: Openagent.pyand complete the script by following the# TODOcomments. Your goal is to define an agent and configure theMcpToolsetto launch and connect to the file system server.import os
# TODO: 1. Import the necessary classes:
from google.adk import Agent
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from mcp import StdioServerParameters
# -- Configuration --
# TODO: 2. Define the TARGET_FOLDER_PATH.
TARGET_FOLDER_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "test_files/")
# -- Agent Definition --
# TODO: 3. Define the root_agent.
# Instantiate an Agent with the following properties:
# - model: 'gemini-3.5-flash'
# - name: 'filesystem_agent'
# - instruction: 'You are a helpful assistant that can interact with a user\'s local file system. You can list files and read their content.'
# - tools: A list containing one item: the McpToolset.
# Inside the Agent's `tools` list, you will configure the McpToolset.
# Follow this structure:
#
# McpToolset(
# connection_params=StdioConnectionParams(
# server_params=StdioServerParameters(
# # TODO: 4. Set the `command` to 'npx'.
# # TODO: 5. Set the `args` to a list containing:
# # "-y", "@modelcontextprotocol/server-filesystem", absolute path to TARGET_FOLDER_PATH
# command=...,
# args=[...],
# ),
# ),
# # TODO: 6. Optionally, filter specific tools: 'list_directory' and 'read_file'.
# tool_filter=[...]
# )
root_agent = ... -
Set up your
.envfile with your API key or Agent Platform project.
Step 4: Test the Stateful Tool
-
Navigate to the parent directory (
cd ..) and start the Dev UI:uv run adk webWhen the server starts, you will see output in the console as
npxdownloads and runs the@modelcontextprotocol/server-filesystempackage.Note: if your very first request fails with an MCP session timeout, this is likely
npxdownloading the server package for the first time. Simply retry — it will be fast on every subsequent run since the package stays cached locally. -
Interact with the agent:
- Open the Dev UI in your browser.
- Select the
filesystem_agentfrom the dropdown. - Turn 1: List the files.
- User: "What files are in my directory?"
- Expected Response: The agent should respond with a message indicating that it sees
hello.txt.
- Turn 2: Read the file.
- User: "Great, can you read the content of hello.txt for me?"
- Expected Response: The agent should respond with the content of the file: "Hello from the MCP world!"
-
Examine the Trace View:
- In the trace for both turns, you will see
execute_toolsteps forlist_directoryandread_file. These tools were dynamically discovered by theMcpToolset.
- In the trace for both turns, you will see
Having Trouble?
If you get stuck, you can find the complete, working code in the lab-solution.md file.
Lab Summary
You have successfully connected your ADK agent to a stateful, external tool using the Model Context Protocol.
You have learned to:
- Understand the client-server architecture of MCP.
- Use the
McpToolsetto connect to an MCP server. - Configure the
StdioConnectionParamsto automatically launch a local MCP server process directly within your agent definition. - Build an agent that can use tools provided by an external service without having to define them locally.
Bonus: Connecting to a Remote MCP Server
So far you connected to a local MCP server launched as a subprocess (StdioConnectionParams). Most real-world integrations instead connect to a server already running somewhere else over HTTP, using StreamableHTTPConnectionParams — same McpToolset, different transport.
-
Get a free GitHub Personal Access Token: create one at github.com/settings/personal-access-tokens/new with read-only repository access.
-
Set it as an environment variable in your
.envfile:GITHUB_TOKEN=YOUR_GITHUB_TOKEN -
Create a second agent (e.g.
github_agent/agent.py):import os
from google.adk import Agent
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
GITHUB_TOKEN = os.environ["GITHUB_TOKEN"]
root_agent = Agent(
model="gemini-3.5-flash",
name="github_agent",
instruction="Help users get information from GitHub repositories.",
tools=[
McpToolset(
connection_params=StreamableHTTPConnectionParams(
url="https://api.githubcopilot.com/mcp/",
headers={
"Authorization": f"Bearer {GITHUB_TOKEN}",
"X-MCP-Readonly": "true",
},
),
)
],
) -
Try it: ask "What are the open issues on google/adk-python?" — no
npx, no subprocess, no local sandboxing: the tool call goes straight over HTTPS to GitHub's servers.
A few things change when the server is remote instead of local: there's no subprocess lifecycle to manage (the server runs independently of your agent), network failures (timeouts, rate limits, an expired token) become a real possibility that a local stdio server never has, and the security surface shifts from "the subprocess has filesystem access" to "don't hardcode the credential in your header" — which is why the token above comes from .env, not a literal string.
Self-Reflection Questions
- The
McpToolsetdynamically discovers the tools from the server. What are the advantages of this approach compared to manually defining each tool on the agent side? - The file system server is "stateful" because it remembers the state of the
test_filesdirectory between tool calls. How does this differ from the stateless calculator tools you built in earlier modules? - The
StdioConnectionParamslaunches the MCP server as a subprocess. What are the security implications of this, and why is it important that the server is sandboxed to a specificTARGET_FOLDER_PATH?
🕵️ Hidden Solution 🕵️
Looking for the solution? Here's a hint (Base64 decode me):
L2RvYy1hZGstdHJhaW5pbmcvbW9kdWxlMjctaW50cm8tdG8tbWNwL2xhYi1zb2x1dGlvbg==
The direct link is: Lab Solution