chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:25:13 +08:00
commit ec2b666284
2231 changed files with 491535 additions and 0 deletions
@@ -0,0 +1,52 @@
# FastMCP Server-Side Sampling with ADK
This project demonstrates how to use server-side sampling with a `fastmcp` server connected to an ADK `MCPToolset`.
## Description
The setup consists of two main components:
1. **ADK Agent (`agent.py`):** An `LlmAgent` is configured with an `MCPToolset`. This toolset connects to a local `fastmcp` server.
1. **FastMCP Server (`mcp_server.py`):** A `fastmcp` server that exposes a single tool, `analyze_sentiment`. This server is configured to use its own LLM for sampling, independent of the ADK agent's LLM.
The flow is as follows:
1. The user provides a text prompt to the ADK agent.
1. The agent decides to use the `analyze_sentiment` tool from the `MCPToolset`.
1. The tool call is sent to the `mcp_server.py`.
1. Inside the `analyze_sentiment` tool, `ctx.sample()` is called. This delegates an LLM call to the `fastmcp` server's own sampling handler.
1. The `mcp_server`'s LLM processes the prompt from `ctx.sample()` and returns the result to the server.
1. The server processes the LLM response and returns the final sentiment to the agent.
1. The agent displays the result to the user.
## Steps to Run
### Prerequisites
- Python 3.10+
- `google-adk` library installed.
- A configured OpenAI API key.
### 1. Set up the Environment
Clone the project and navigate to the directory. Make sure your `OPENAI_API_KEY` is available as an environment variable.
### 2. Install Dependencies
Install the required Python libraries:
```bash
pip install fastmcp openai litellm
```
### 3. Run the Example
Navigate to the `samples` directory and choose this ADK agent:
```bash
adk web .
```
The agent will automatically start the FastMCP server in the background.
- **Sample user prompt:** "What is the sentiment of 'I love building things with Python'?"
@@ -0,0 +1,15 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import agent
+56
View File
@@ -0,0 +1,56 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os
from google.adk.agents import LlmAgent
from google.adk.models.lite_llm import LiteLlm
from google.adk.tools.mcp_tool import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from mcp import StdioServerParameters
# This example uses the OpenAI API for both the agent and the server.
# Ensure your OPENAI_API_KEY is available as an environment variable.
api_key = os.getenv('OPENAI_API_KEY')
if not api_key:
raise ValueError('The OPENAI_API_KEY environment variable must be set.')
# Configure the StdioServerParameters to start the mcp_server.py script
# as a subprocess. The OPENAI_API_KEY is passed to the server's environment.
server_params = StdioServerParameters(
command='python',
args=['mcp_server.py'],
env={'OPENAI_API_KEY': api_key},
)
# Create the ADK MCPToolset, which connects to the FastMCP server.
# The `tool_filter` ensures that only the 'analyze_sentiment' tool is exposed
# to the agent.
mcp_toolset = MCPToolset(
connection_params=StdioConnectionParams(
server_params=server_params,
),
tool_filter=['analyze_sentiment'],
)
# Define the ADK agent that uses the MCP toolset.
root_agent = LlmAgent(
model=LiteLlm(model='openai/gpt-4o'),
name='SentimentAgent',
instruction=(
'You are an expert at analyzing text sentiment. Use the'
' analyze_sentiment tool to classify user input.'
),
tools=[mcp_toolset],
)
@@ -0,0 +1,81 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import os
from fastmcp import Context
from fastmcp import FastMCP
from fastmcp.experimental.sampling.handlers.openai import OpenAISamplingHandler
from openai import OpenAI
logging.basicConfig(level=logging.INFO)
API_KEY = os.getenv("OPENAI_API_KEY")
# Set up the server's LLM handler using the OpenAI API.
# This handler will be used for all sampling requests from tools on this server.
llm_handler = OpenAISamplingHandler(
default_model="gpt-4o",
client=OpenAI(
api_key=API_KEY,
),
)
# Create the FastMCP Server instance.
# The `sampling_handler` is configured to use the server's own LLM.
# `sampling_handler_behavior="always"` ensures the server never delegates
# sampling back to the ADK agent.
mcp = FastMCP(
name="SentimentAnalysis",
sampling_handler=llm_handler,
sampling_handler_behavior="always",
)
@mcp.tool
async def analyze_sentiment(text: str, ctx: Context) -> dict:
"""Analyzes sentiment by delegating to the server's own LLM."""
logging.info("analyze_sentiment tool called with text: %s", text)
prompt = f"""Analyze the sentiment of the following text as positive,
negative, or neutral. Just output a single word.
Text to analyze: {text}"""
# This delegates the LLM call to the server's own sampling handler,
# as configured in the FastMCP instance.
logging.info("Attempting to call ctx.sample()")
try:
response = await ctx.sample(prompt)
logging.info("ctx.sample() successful. Response: %s", response)
except Exception as e:
logging.error("ctx.sample() failed: %s", e, exc_info=True)
raise
sentiment = response.text.strip().lower()
if "positive" in sentiment:
result = "positive"
elif "negative" in sentiment:
result = "negative"
else:
result = "neutral"
logging.info("Sentiment analysis result: %s", result)
return {"text": text, "sentiment": result}
if __name__ == "__main__":
print("Starting FastMCP server with tool 'analyze_sentiment'...")
# This runs the server process, which the ADK agent will connect to.
mcp.run()