Skip to main content

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โ€‹

Environment setup:

  • Local machine: If you're continuing the course in sequence, cd into the adk-training project you created in Module 2 and skip the block below -- your environment and dependencies already carry forward. If you're starting fresh at this module, create that project first:
    uv init adk-training --python 3.10 && cd adk-training
    uv add "google-adk>=2.1.0" python-dotenv
  • DevContainer / Codespaces (Alternative): If you opened this repository in a DevContainer or GitHub Codespaces, Python, uv, and the core ADK dependencies are already pre-installed in your container environment.
  1. Navigate to your training directory:

    cd /path/to/your/adk-training
  2. Create the agent project:

    uv run adk create mcp_agent
    cd mcp_agent
  3. Install the MCP extra. mcp is 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.

  1. Create a directory for the tool to access: Inside your mcp_agent project, create a directory named test_files.

    mkdir test_files
  2. Create a sample file: Inside test_files, create a file named hello.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.

  1. Create the agent.py file: In the mcp_agent directory, create a file named agent.py.

  2. Confirm the __init__.py file exists: uv run adk create already generated this empty file for you in Step 1. It's crucial: it tells Python to treat the mcp_agent directory as a package, allowing uv run adk web to discover and load your agent.py.

    ls __init__.py
  3. Complete the agent.py script: Exercise: Open agent.py and complete the script by following the # TODO comments. Your goal is to define an agent and configure the McpToolset to 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 = ...
  4. Set up your .env file with your API key or Agent Platform project.

Step 4: Test the Stateful Toolโ€‹

  1. Navigate to the parent directory (cd ..) and start the Dev UI:

    uv run adk web

    When the server starts, you will see output in the console as npx downloads and runs the @modelcontextprotocol/server-filesystem package.

    Note: if your very first request fails with an MCP session timeout, this is likely npx downloading the server package for the first time. Simply retry โ€” it will be fast on every subsequent run since the package stays cached locally.

  2. Interact with the agent:

    • Open the Dev UI in your browser.
    • Select the filesystem_agent from 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. Note that the discovered list_directory tool takes a generic path argument with no hint of what "my directory" maps to, so the agent may instead ask a clarifying question like "Which directory would you like me to look into?" -- if that happens, just reply "the current directory" (or rephrase your first message to something less ambiguous, like "List the files in the directory you have access to").
    • 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!"
  3. Examine the Trace View:

    • In the trace for both turns, you will see execute_tool steps for list_directory and read_file. These tools were dynamically discovered by the McpToolset.

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 McpToolset to connect to an MCP server.
  • Configure the StdioConnectionParams to 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.

  1. Get a free GitHub Personal Access Token: create one at github.com/settings/personal-access-tokens/new with read-only repository access.

  2. Set it as an environment variable in your .env file:

    GITHUB_TOKEN=YOUR_GITHUB_TOKEN
  3. 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",
    },
    ),
    )
    ],
    )
  4. 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 McpToolset dynamically 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_files directory between tool calls. How does this differ from the stateless calculator tools you built in earlier modules?
  • The StdioConnectionParams launches 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 specific TARGET_FOLDER_PATH?

๐Ÿ” Reference Solution Vaultโ€‹

๐Ÿ”

Module 27 Reference Solution Vault

Active Comprehension Gate โ€ข Zero Guessable URLs โ€ข Guided Verification

Step 1/3: Question 1 of 3

In Module 27 (Intro to MCP), what is the primary role of MCP client-server architecture in ADK architectures?