Google GenAI SDK wrapper for integrating the Model Context Protocol (MCP)
Project description
Gemini MCP Relay
gemini-mcp-relay is a Python SDK Wrapper and a standalone proxy that seamlessly integrates the Model Context Protocol (MCP) with the official Google GenAI SDK.
It intercepts requests to Google's API, fetches tools from your remote MCP servers, passes them to the model, and autonomously orchestrates the function-calling loop.
Installation
Install via pip. You can choose to install just the core library (for local SDK wrapping) or include the proxy server dependencies.
Install for local Python SDK usage
pip install gemini-mcp-relay
Install with proxy server capabilities
pip install "gemini-mcp-relay[server]"
🔨 Usage Mode 1: Local SDK Wrapper
If you are writing a Python application, you don't need to run a separate server. You can use the MCPClientWrapper to wrap the official google.genai.Client.
The wrapper features a stateful connection pool, meaning it maintains persistent connections to your MCP servers via an async with block.
1. Example: Using MCP servers
import asyncio
from google import genai
from gemini_mcp_relay import MCPClientWrapper
async def main():
# 1. Initialize the standard Google GenAI client
base_client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
# 2. Wrap it with our MCP Client
# Optional: you can also pass pre-configured servers here
# client = MCPClientWrapper(base_client, mcp_servers={"math": {"url": "..."}})
client = MCPClientWrapper(base_client)
# 3. Open the connection pool context
async with client:
# Dynamically add an MCP server (connection stays open)
await client.mcp.add_server("math_server", {
"url": "https://mathematics.fastmcp.app/mcp"
})
# --- You can use single-turn generation ---
# response = await client.models.generate_content(
# model="gemini-3.5-flash",
# contents="What is 125 * 456? Use the calculation tool."
# )
# print("Response:", response.text)
# -------------------------------------------
# --- Or you can use the standard chats module ---
chat = client.chats.create(model="gemini-3.5-flash")
print("Model is thinking...")
response = await chat.send_message("What is 125 * 456? Use the calculate tool.")
print("Response:", response.text)
# You can dynamically add or remove servers on the fly
await client.mcp.remove_server("math_server")
await client.mcp.add_server("search_server", {
"url": "https://mcp.exa.ai/mcp",
"type": "sse", # explicitly tell the proxy to use SSE transport
"headers": {"Authorization": "Bearer YOUR_TOKEN"}
})
response = await chat.send_message("Now search the web for the latest news.")
print("Response:", response.text)
if __name__ == "__main__":
asyncio.run(main())
2. Example: Using MCP servers with local Python tools
MCPClientWrapper fully supports combining remote MCP servers with your own local Python functions. The orchestrator automatically routes the calls to the correct handler, including full support for sync/async functions and Pydantic-model inputs.
import asyncio
from google import genai
from google.genai import types
from gemini_mcp_relay import MCPClientWrapper
# 1. Define a standard local Python tool
def get_user_balance(user_id: str) -> dict:
"""
Retrieve the current account balance for a user.
Args:
user_id: The unique identifier of the user.
"""
# Simply return a mock value
return {"user_id": user_id, "balance_usd": 1250.50}
async def main():
base_client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
client = MCPClientWrapper(base_client)
async with client:
# Connect to a remote MCP server for math calculations
await client.mcp.add_server("math_server", {
"url": "https://mathematics.fastmcp.app/mcp"
})
# Request both the MCP math tool and your local Python function
prompt = (
"First, use the `get_user_balance` tool to look up balance for user 'usr_456'. "
"Then, use the `calculate_expression` tool to double that balance."
)
response = await client.models.generate_content(
model="gemini-3.5-flash",
contents=prompt,
config=types.GenerateContentConfig(
# Register your local Python functions here as standard callables
tools=[get_user_balance]
)
)
print("Response:", response.text)
if __name__ == "__main__":
asyncio.run(main())
🔨 Usage Mode 2: Standalone Proxy Server
If you are building a non-Python application (e.g., Node.js, Go) or simply prefer to run the MCP Relay as a microservice, you can start the built-in FastAPI server.
1. Start the Server
(Requires the [server] installation extra)
gemini-mcp-relay --port 8000
The server is now running and fully emulates the Google API.
2. Connect from any Client
On the client side, replace the Google base_url with the proxy's address (http://127.0.0.1:8000) and pass your MCP configuration via the X-MCP-Servers HTTP header (encoded in Base64).
Python SDK Example:
import base64
import json
from google import genai
# Define your MCP servers
mcp_config = {
"math_server": {
"url": "https://mathematics.fastmcp.app/mcp"
}
}
# Encode to Base64 to pass over HTTP
mcp_header = base64.b64encode(json.dumps(mcp_config).encode("utf-8")).decode("utf-8")
# Connect to the local Proxy Server
client = genai.Client(
api_key="YOUR_GEMINI_API_KEY",
http_options={
"base_url": "http://127.0.0.1:8000",
"headers": {"x-mcp-servers": mcp_header}
}
)
# The server handles the MCP orchestration automatically
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Calculate 15 * 8"
)
print(response.text)
(Note: The server proxy operates in a stateless manner. It will establish and close connections to the MCP servers on every single HTTP request).
Tool Name Conflicts & Disabling
If multiple connected MCP servers provide a tool with the exact same name, gemini-mcp-relay automatically prefixes the tool name with the server's name to prevent conflicts (e.g., two servers with a calculate tool will yield server1_calculate and server2_calculate).
Disabling Tools
You can manually prevent specific tools from being passed to the model. Thanks to the conflict resolution logic, you have granular control:
- Global Exclusion: Use the original tool name (e.g.,
"calculate") to disable it across all connected servers. - Server-Specific Exclusion: Use the prefixed name (e.g.,
"server1_calculate") to disable it only for that specific server.
When using the wrapper locally, with excluded_tools you can dynamically add or remove excluded tools at any time, and the internal state will update for the next model generation.
# 1. Initialize with a pre-configured exclusion list
client = MCPClientWrapper(base_client, excluded_tools=["unsafe_tool", "server1_calculate"])
# 2. Add an exclusion dynamically
client.mcp.excluded_tools.add("dangerous_action")
# 3. Remove an exclusion dynamically (allow the tool again)
client.mcp.excluded_tools.remove("unsafe_tool")
# 4. Clear all exclusions (allow all tools)
client.mcp.excluded_tools.clear()
# 5. Add multiple exclusions at once
client.mcp.excluded_tools.update(["t1", "t2"])
Via Standalone Server
When connecting to the relay via HTTP, pass a Base64-encoded JSON array of excluded tool names to the X-MCP-Excluded-Tools header on each request.
MCP Servers Resources Support
If a connected MCP server supports resources, gemini-mcp-relay automatically injects two additional tools into the model:
list_resources— allows the model to view available server resources.read_resource— allows the model to read the content of a specific resource via its URI.
Tracing Tool Execution
Whether you are using the Local SDK Wrapper or connecting via the Standalone Proxy Server, the tool execution lifecycle remains completely transparent. Because the library executes tools autonomously on your behalf, it automatically injects the intermediate function_call and function_response steps directly into the final response (or SSE stream chunks).
This allows your application to perfectly trace and log exactly which MCP tools were used behind the scenes.
for part in response.candidates[0].content.parts:
if part.function_call:
print(f"[🔧 Tool Executed: {part.function_call.name}]")
elif part.function_response:
print(f"[✅ Tool Result]: {part.function_response.response}")
elif part.text:
print(part.text)
Retrieving Available Tools
You can retrieve a list of all active tools (and their JSON schemas) that are currently available to the model.
Locally:
Use the get_tools method. You can optionally pass a server name to filter the results.
# Get all tools across all servers
all_tools = client.mcp.get_tools()
# Get tools from a specific server
math_tools = client.mcp.get_tools("math_server")
for tool in math_tools:
print(f"Tool: {tool['name']}")
print(f"Schema: {tool['parameters']}")
Via Server:
If you are using the standalone proxy, use the GET /v1/mcp/tools HTTP endpoint.
curl http://127.0.0.1:8000/v1/mcp/tools \
-H "X-MCP-Servers: <BASE64_ENCODED_CONFIG>"
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gemini_mcp_relay-0.1.0.tar.gz.
File metadata
- Download URL: gemini_mcp_relay-0.1.0.tar.gz
- Upload date:
- Size: 24.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
759660caf4a9b6c66cbb9e0ef35cf2755307926995800c93c3c0797a9fa77d7c
|
|
| MD5 |
c90b85f560be6a83a8b5c32e59d2255e
|
|
| BLAKE2b-256 |
02d71a1919bd0365bdf18d37112f45c67751e81f3d76034b5b93c1d31b2251d6
|
File details
Details for the file gemini_mcp_relay-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gemini_mcp_relay-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e41d192d0004212a3ff26907f228d2fecd754f4d1d7ac4950d5fbf2d89dd3a77
|
|
| MD5 |
de1db1ee1cba7507bf61d4dea52066b2
|
|
| BLAKE2b-256 |
7910230d98fb73aa32f8276c50c671e7a8cb1b57cf25192c1661cc2235ed6dcf
|