- Updated: April 30, 2025
- 5 min read
Creating Custom MCP Clients with Gemini: A Guide to Enhancing AI Development
Unlocking the Power of Custom MCP Clients with Gemini API
In the ever-evolving landscape of AI development, creating custom Model Context Protocol (MCP) Clients using the Gemini API is becoming increasingly vital. These custom clients enable AI developers and researchers to connect their applications with MCP servers, unlocking powerful capabilities to supercharge their projects. This article delves into the importance of custom MCP Clients, the setup process, and the impact on AI applications.

Understanding the Importance of Custom MCP Clients
Custom MCP Clients are essential for AI developers who want to leverage the full potential of the Gemini API. These clients allow for seamless integration with various MCP servers, enabling developers to harness unique tools and capabilities tailored to their specific needs. By creating custom MCP Clients, developers can enhance their AI applications’ functionality, efficiency, and scalability.
Setting Up Your Environment and Dependencies
Before diving into the implementation, setting up the environment and dependencies is crucial. Here’s a step-by-step guide:
- Gemini API Key: Obtain your Gemini API key by visiting Google’s Gemini API Key page. Store it safely as it will be needed later.
- Node.js: Download the latest version of Node.js from nodejs.org and run the installer with default settings.
- National Park Services API: Request an API key by visiting the National Park Service API page. Keep this key accessible for later use.
-
Python Libraries: Install the necessary Python libraries by running the following command:
pip install mcp python-dotenv google-genai
Implementation Steps and Best Practices
With the environment set up, it’s time to implement the MCP Client. Follow these steps for a successful implementation:
Creating Configuration Files
Start by creating an mcp.json file to store configuration details about the MCP servers your client will connect to. Add the following content:
{
"mcpServers": {
"nationalparks": {
"command": "npx",
"args": ["-y", "mcp-server-nationalparks"],
"env": {
"NPS_API_KEY": ""
}
}
}
}
Replace <YOUR_NPS_API_KEY> with the key you generated. Next, create a .env file in the same directory and add:
GEMINI_API_KEY = <YOUR_GEMINI_API_KEY>
Replace <YOUR_GEMINI_API_KEY> with your Gemini API key.
Implementing the MCP Client
Create a client.py file to implement the MCP Client. Ensure it is in the same directory as mcp.json and .env.
Begin by importing necessary libraries and creating a basic client class:
import asyncio
import json
import os
from typing import List, Optional
from contextlib import AsyncExitStack
import warnings
from google import genai
from google.genai import types
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from dotenv import load_dotenv
load_dotenv()
warnings.filterwarnings("ignore", category=ResourceWarning)
def clean_schema(schema):
allowed_keys = {"type", "properties", "required", "description", "title", "default", "enum"}
return {k: v for k, v in schema.items() if k in allowed_keys}
class MCPGeminiAgent:
def __init__(self):
self.session: Optional[ClientSession] = None
self.exit_stack = AsyncExitStack()
self.genai_client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))
self.model = "gemini-2.0-flash"
self.tools = None
self.server_params = None
self.server_name = None
The __init__ method initializes the MCPGeminiAgent by setting up an asynchronous session manager, loading the Gemini API client, and preparing placeholders for model configuration, tools, and server details.
Connecting to the MCP Server
Establish an asynchronous connection to the selected MCP server using stdio transport. Initialize the MCP session and retrieve the available tools from the server.
async def connect(self):
await self.select_server()
self.stdio_transport = await self.exit_stack.enter_async_context(stdio_client(self.server_params))
self.stdio, self.write = self.stdio_transport
self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))
await self.session.initialize()
print(f"Successfully connected to: {self.server_name}")
mcp_tools = await self.session.list_tools()
print("\nAvailable MCP tools for this server:")
for tool in mcp_tools.tools:
print(f"- {tool.name}: {tool.description}")
Handling User Queries and Tool Calls
This method sends the user’s prompt to Gemini, processes any tool calls returned by the model, executes the corresponding MCP tools, and iteratively refines the response.
async def agent_loop(self, prompt: str) -> str:
contents = [types.Content(role="user", parts=[types.Part(text=prompt)])]
mcp_tools = await self.session.list_tools()
tools = types.Tool(function_declarations=[
{
"name": tool.name,
"description": tool.description,
"parameters": clean_schema(getattr(tool, "inputSchema", {}))
} for tool in mcp_tools.tools
])
self.tools = tools
response = await self.genai_client.aio.models.generate_content(
model=self.model,
contents=contents,
config=types.GenerateContentConfig(
temperature=0,
tools=[tools],
),
)
contents.append(response.candidates[0].content)
turn_count = 0
max_tool_turns = 5
while response.function_calls and turn_count = max_tool_turns and response.function_calls:
print(f"Stopped after {max_tool_turns} tool calls to avoid infinite loops.")
print("All tool calls complete. Displaying Gemini's final response.")
return response
Interactive Chat Loop
This provides a
Andrii Bidochko
CTO UBOS
Andrii Bidochko is an AI entrepreneur and researcher focused on AI agents, reinforcement learning, and autonomous systems. He writes about the technologies shaping the future of machine intelligence, from frontier models and agent architectures to real-world AI applications.