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,76 @@
# MCP SSE Agent with mTLS
This sample demonstrates how to configure an ADK agent to connect to an MCP server using **mutual TLS (mTLS)** over SSE (HTTPS).
## Prerequisites
To test mTLS locally, you need to generate local certificates (CA, Server, and Client) and configure your environment to trust them.
### 1. Generate Certificates
Run the helper script in this directory to generate a local CA and sign the server and client certificates:
```bash
./generate_mtls_certs.sh
```
This will generate:
- `ca.crt`, `ca.key` (Local CA)
- `server.crt`, `server.key` (Server certificate/key)
- `client.crt`, `client.key` (Client certificate/key)
- `certificate_config.json` (Workload certificate configuration for `google-auth`)
______________________________________________________________________
## Running the Sample
### Step 1: Start the MCP Server
Start the server in this directory. We configure it to trust our local CA so it can verify the client certificate:
```bash
# Point to the certificate config
export GOOGLE_API_CERTIFICATE_CONFIG=$(pwd)/certificate_config.json
# Tell the server to trust our test CA for client verification
export SSL_CA_CERTS=$(pwd)/ca.crt
# Run the server
python filesystem_server.py
```
*(The server will run on `https://localhost:3000`)*
### Step 2: Run the ADK Agent (Client)
In a second terminal, navigate to the open-source workspace root and run the client.
```bash
cd third_party/py/google/adk/open_source_workspace
source .venv/bin/activate
# 1. Combine system CAs with our test CA so the client trusts the server cert
cat /usr/lib/ssl/cert.pem contributing/samples/mcp/mcp_sse_mtls_agent/ca.crt > combined_ca.pem
export SSL_CERT_FILE=$(pwd)/combined_ca.pem
# 2. Point google-auth to our simulated workload config
export GOOGLE_API_CERTIFICATE_CONFIG=$(pwd)/contributing/samples/mcp/mcp_sse_mtls_agent/certificate_config.json
# 3. Enable client certificate usage
export GOOGLE_API_USE_CLIENT_CERTIFICATE=true
# 4. Set your LLM credentials (e.g. source your env file)
source test/.env
# 5. Run the agent
adk run contributing/samples/mcp/mcp_sse_mtls_agent
```
______________________________________________________________________
## How it works
1. **Client Certificate (mTLS):** The `google-auth` library (used by ADK) reads `GOOGLE_API_CERTIFICATE_CONFIG` to load the client certificate (`client.crt`) and key (`client.key`) as a simulated Workload Certificate.
1. **Server Verification:** The server loads the CA (`ca.crt`) via `SSL_CA_CERTS` and requires the client to present a certificate signed by this CA (`ssl_cert_reqs=ssl.CERT_REQUIRED`).
1. **Client Verification:** The client trusts the server certificate (`server.crt`) because it is signed by the same CA, which we added to `SSL_CERT_FILE`.
@@ -0,0 +1,45 @@
# 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.llm_agent import LlmAgent
from google.adk.agents.mcp_instruction_provider import McpInstructionProvider
from google.adk.tools.mcp_tool.mcp_session_manager import SseConnectionParams
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
connection_params = SseConnectionParams(
url=os.environ.get('MCP_SERVER_URL', 'https://localhost:3000/sse'),
headers={'Accept': 'text/event-stream'},
)
root_agent = LlmAgent(
name='enterprise_assistant',
model='gemini-2.5-flash',
instruction=McpInstructionProvider(
connection_params=connection_params,
prompt_name='file_system_prompt',
),
tools=[
MCPToolset(
connection_params=connection_params,
tool_filter=[
'read_file',
'list_directory',
'get_cwd',
],
)
],
)
@@ -0,0 +1,151 @@
# 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 asyncio
import os
import pathlib
import ssl
import sys
import tempfile
import google.auth.transport.mtls as google_mtls
from mcp.server.fastmcp import FastMCP
import uvicorn
# Create an MCP server with a name
mcp = FastMCP("Filesystem Server (mTLS)", host="localhost", port=3000)
# Add a tool to read file contents
@mcp.tool(description="Read contents of a file")
def read_file(filepath: str) -> str:
"""Read and return the contents of a file."""
with open(filepath, "r") as f:
return f.read()
# Add a tool to list directory contents
@mcp.tool(description="List contents of a directory")
def list_directory(dirpath: str) -> list:
"""List all files and directories in the given directory."""
return os.listdir(dirpath)
# Add a tool to get current working directory
@mcp.tool(description="Get current working directory")
def get_cwd() -> str:
"""Return the current working directory."""
return str(pathlib.Path.cwd())
# Add a prompt for accessing file systems
@mcp.prompt()
def file_system_prompt() -> str:
"""Prompt helper for accessing file systems."""
return (
"You are a helpful assistant with access to the local filesystem. You can"
" read files and list directories to help the user with their request."
)
# Graceful shutdown handler
async def shutdown(signal, loop):
"""Cleanup tasks on shutdown."""
print(f"\nReceived exit signal {signal.name}...")
tasks = [t for t in asyncio.all_tasks() if t is not asyncio.current_task()]
for task in tasks:
task.cancel()
print(f"Cancelling {len(tasks)} outstanding tasks")
await asyncio.gather(*tasks, return_exceptions=True)
loop.stop()
# Main entry point with mTLS enabled
if __name__ == "__main__":
cert_dir = os.path.dirname(os.path.abspath(__file__))
keyfile = os.path.join(cert_dir, "server.key")
certfile = os.path.join(cert_dir, "server.crt")
if not (os.path.exists(keyfile) and os.path.exists(certfile)):
print(f"Error: mTLS cert files not found in {cert_dir}")
print("Please generate them using the helper script:")
print(f" ./generate_mtls_certs.sh")
sys.exit(1)
# Configure SSL context for mTLS
print("Configuring SSL context for mTLS...")
# Allow explicit CA certs override (useful for testing with custom CA signed certs)
ca_certs = os.environ.get("SSL_CA_CERTS")
temp_ca_file = None
if ca_certs:
print(f" Using explicit SSL_CA_CERTS: {ca_certs}")
else:
has_cert_source = google_mtls.has_default_client_cert_source()
print(f" has_default_client_cert_source: {has_cert_source}")
print(f" default cafile: {ssl.get_default_verify_paths().cafile}")
if has_cert_source:
try:
callback = google_mtls.default_client_cert_source()
client_cert_bytes, _ = callback()
temp_ca_file = tempfile.NamedTemporaryFile(delete=False, suffix=".crt")
temp_ca_file.write(client_cert_bytes)
temp_ca_file.close()
ca_certs = temp_ca_file.name
print(f" Loaded client cert to trust: {ca_certs}")
except Exception as e:
print(f" Warning: Failed to load default client cert: {e}")
ca_certs = ssl.get_default_verify_paths().cafile
else:
print(" No default client cert source found. Using system CAs.")
ca_certs = ssl.get_default_verify_paths().cafile
print(f" Using ca_certs for client verification: {ca_certs}")
app = mcp.sse_app()
config = uvicorn.Config(
app,
host=mcp.settings.host,
port=mcp.settings.port,
log_level=mcp.settings.log_level.lower(),
ssl_keyfile=keyfile,
ssl_certfile=certfile,
ssl_cert_reqs=int(ssl.CERT_REQUIRED),
ssl_ca_certs=ca_certs,
)
server = uvicorn.Server(config)
print(
"Starting MCP server with mTLS on"
f" https://{mcp.settings.host}:{mcp.settings.port}"
)
try:
asyncio.run(server.serve())
except KeyboardInterrupt:
print("\nServer shutting down gracefully...")
except Exception as e:
print(f"Unexpected error: {e}")
sys.exit(1)
finally:
if temp_ca_file:
try:
os.unlink(temp_ca_file.name)
print(f"Cleaned up temp CA file: {temp_ca_file.name}")
except OSError:
pass
print("Thank you for using the Filesystem MCP Server!")
@@ -0,0 +1,56 @@
#!/bin/bash
# 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.
set -e
# Directory where this script is located
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$DIR"
echo "Generating certificates in $DIR..."
# 1. Create CA
openssl req -x509 -new -nodes -newkey rsa:2048 -keyout ca.key -sha256 -days 365 -out ca.crt -subj '/CN=TestCA'
# 2. Create Server Cert
openssl req -new -nodes -newkey rsa:2048 -keyout server.key -out server.csr -subj '/CN=localhost'
# Sign with CA
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256
# 3. Create Client Cert
openssl req -new -nodes -newkey rsa:2048 -keyout client.key -out client.csr -subj '/CN=TestClient'
# Sign with CA
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 365 -sha256
# Clean up CSRs and serial file
rm -f server.csr client.csr ca.srl
# 4. Create certificate_config.json
cat <<EOF > certificate_config.json
{
"cert_configs": {
"workload": {
"cert_path": "$DIR/client.crt",
"key_path": "$DIR/client.key"
}
}
}
EOF
echo "Done! Generated:"
echo " - ca.crt, ca.key (CA)"
echo " - server.crt, server.key (Server cert)"
echo " - client.crt, client.key (Client cert)"
echo " - certificate_config.json (Workload config for google-auth)"