Gemini Enterprise Hairpin MCP Proxy for Google SecOps
Provides a proxy for Google SecOps OneMCP that strips bloated tool schemas, enabling agents to list and call Google Security Operations tools with a significantly reduced payload while preserving tool names, descriptions, and annotations.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Gemini Enterprise Hairpin MCP Proxy for Google SecOpswhat Google SecOps OneMCP tools can I use?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Gemini Enterprise Hairpin MCP Proxy for Google SecOps
When you connect an Agent Development Kit (ADK) agent or Gemini Enterprise connector directly to the Google Security Operations OneMCP server at https://us-chronicle.googleapis.com/mcp, the tools/list response returns 71 tools totaling 4.13 MB of JSON (3.74 MB of outputSchema and 243 KB of inputSchema).
When ADK converts those MCP tool definitions into Gemini function declarations, it passes both inputSchema and outputSchema to Vertex AI. Vertex AI rejects the request with 400 INVALID_ARGUMENT because the combined schemas exceed the model's schema state limit.
This repository provides a Hairpin MCP Proxy on Cloud Run that unblocks using Gemini Enterprise MCP connectors with Google SecOps OneMCP:
Strips bloated schemas server-side: Forwards JSON-RPC 2.0 requests to
https://us-chronicle.googleapis.com/mcp, removesoutputSchemafromtools/list, and replacesinputSchemawith an open object stub ({"type": "object", "additionalProperties": true}).Reduces
tools/listpayload by 96.52%: Shrinks thetools/listpayload from4,125,239 bytes(4.13 MB) to143,464 bytes(143.5 KB) while preserving all 71 tool names, descriptions, and annotations.Registers as a Gemini Enterprise connector: Registers in Discovery Engine as a
custom_mcp(BYO_MCP) connector and syncs automatically to the Gemini Enterprise Agent Registry catalog.Enforces Cloud Run IAM (
--no-allow-unauthenticated): Requiresroles/run.invokerwith an OIDC ID token inAuthorizationwhile forwarding the caller's OAuth 2.0 access token to OneMCP viaX-Forwarded-Authorization.
flowchart LR
Agent["ADK Agent / Vertex AI Agent Engine"] -->|1. Resolve connector URL| GE["Gemini Enterprise\n(Agent Registry & Discovery Engine)"]
Agent -->|2. JSON-RPC 2.0 + OIDC & OAuth| Proxy["Cloud Run Hairpin MCP Proxy\nPOST /mcp (--no-allow-unauthenticated)"]
Proxy -->|3. Forward JSON-RPC 2.0| OneMCP["Google SecOps OneMCP\nhttps://us-chronicle.googleapis.com/mcp"]
OneMCP -->|4.13 MB tools/list| Proxy
Proxy -->|143.5 KB stripped tools/list| AgentPrerequisites
Local tools: gcloud, uv, just, direnv, curl, and jq (verification commands). uv installs Python 3.11 on demand.
Google Cloud project state:
A Google SecOps (Chronicle) instance linked to the project, and Gemini Enterprise available in the project. Confirm with your Google account team that the project can register custom (
BYO_MCP) connectors and call the SecOps OneMCP endpoint.APIs enabled:
PROJECT_ID="your-gcp-project-id"
gcloud services enable \
run.googleapis.com cloudbuild.googleapis.com artifactregistry.googleapis.com \
discoveryengine.googleapis.com agentregistry.googleapis.com \
aiplatform.googleapis.com chronicle.googleapis.com storage.googleapis.com \
--project="$PROJECT_ID"An operator account that can deploy Cloud Run services, grant project IAM bindings (
just setup-iamedits the project policy), create Cloud Storage buckets, and create Discovery Engine collections and Vertex AI reasoning engines.roles/owneron a sandbox project satisfies all of these.
Related MCP server: fde-assessment
Quickstart: Repeat the Hairpin MCP setup
1. Initialize local environment
just setup
direnv allow ..envrc activates ./.venv and isolates gcloud configuration and Application Default Credentials to ./.gcloud (gitignored). Edit .env and set GCP_PROJECT_ID; CHRONICLE_CUSTOMER_ID is only substituted into example prompts and verification commands, and GCP_PROJECT_NUMBER, CLOUDSDK_CORE_ACCOUNT, and GCP_STAGING_BUCKET are optional. Then authenticate once from inside the repository directory so the credentials land in the isolated configuration:
ACCOUNT="user@example.com"
gcloud auth login "$ACCOUNT" --update-adcIn non-interactive shells (CI, scripts, coding agents) the direnv hook does not run; prefix commands with direnv exec . to load the same environment.
2. Deploy the Hairpin MCP proxy to Cloud Run
Deploy the FastAPI proxy (src/secops_hairpin_mcp/hairpin.py) to Cloud Run with --no-allow-unauthenticated:
SERVICE_NAME="secops-hairpin-mcp"
just deploy-cloud-run "$SERVICE_NAME"3. Configure IAM and Cloud Run invoker bindings
just setup-iam grants roles/discoveryengine.viewer, roles/agentregistry.viewer, roles/chronicle.viewer, roles/aiplatform.user, roles/mcp.toolUser, and roles/serviceusage.serviceUsageConsumer on the project to your account, the default compute service account (the Cloud Run runtime identity), and the Vertex AI Agent Engine service agent. It then grants roles/run.invoker on the service to those identities and the Discovery Engine service agent, and removes any allUsers invoker binding:
ACCOUNT="user@example.com"
SERVICE_NAME="secops-hairpin-mcp"
just setup-iam "$ACCOUNT" "$SERVICE_NAME"The flow was validated in a project where some of these bindings already existed. If a later step fails with PERMISSION_DENIED, the error names the missing permission; add the corresponding role for the identity shown in the error and rerun the step.
Retrieve the deployed Cloud Run URL and set HAIRPIN_MCP_URL in .env:
PROJECT_ID="your-gcp-project-id"
REGION="us-central1"
SERVICE_NAME="secops-hairpin-mcp"
SERVICE_URL="$(gcloud run services describe "$SERVICE_NAME" --project="$PROJECT_ID" --region="$REGION" --format='value(status.url)')"
HAIRPIN_MCP_URL="${SERVICE_URL}/mcp"
echo "HAIRPIN_MCP_URL=$HAIRPIN_MCP_URL"4. Register the Hairpin MCP connector in Gemini Enterprise
Register the Cloud Run /mcp endpoint as a custom_mcp (BYO_MCP) connector in Discovery Engine (collections:setUpDataConnector). The --hairpin-url flag is only needed when HAIRPIN_MCP_URL is not yet set in .env:
just register-connector --hairpin-url "$HAIRPIN_MCP_URL"Verify that the connector is synced into Gemini Enterprise Agent Registry (the entry appears as Custom MCP Server - secops-hairpin-mcp, usually within a minute):
just list-connectors5. Run the ADK agent locally or deploy to Vertex AI Agent Engine
Run a test prompt locally against the registered Gemini Enterprise Hairpin MCP connector:
just run-agent "What SecOps tools do you have access to?"Deploy the unmodified ADK agent to Vertex AI Agent Engine (Reasoning Engine):
DISPLAY_NAME="secops-hairpin-mcp-vanilla-agent"
just deploy-reasoning-engine --display-name "$DISPLAY_NAME"Agent Engine uploads the packaged agent to a Cloud Storage staging bucket (GCP_STAGING_BUCKET in .env, default gs://<GCP_PROJECT_ID>-agent-engine-staging). The command creates the bucket in the deployment region if it does not exist yet. Copy the printed resource name into REASONING_ENGINE_ID in .env; the verification commands in docs/deployment.md and just teardown read it from there.
6. Teardown
Delete the reasoning engine named by REASONING_ENGINE_ID, the Discovery Engine collection (which removes the Agent Registry entry), and the Cloud Run service:
SERVICE_NAME="secops-hairpin-mcp"
COLLECTION_ID="secops-hairpin-mcp"
just teardown "$SERVICE_NAME" "$COLLECTION_ID"The recipe leaves the staging bucket, the container images in Artifact Registry, and the Cloud Build source uploads in place and prints the commands that remove them.
Security notes
The service is deployed with
--no-allow-unauthenticated. Only identities withroles/run.invokeron the service can reach it; Cloud Run verifies the OIDC ID token inAuthorizationbefore the container sees the request.The proxy calls OneMCP with the OAuth 2.0 access token from
X-Forwarded-Authorizationwhen present (the ADK agent and Agent Engine send it), so SecOps enforces the end user's Chronicle permissions. When no token is forwarded, the proxy falls back to the Cloud Run runtime service account's credentials. Any invoker that omits the header therefore acts with that service account's Chronicle role (roles/chronicle.vieweras granted byjust setup-iam); keep the invoker list short.tools/listresponses are cached in the container for 300 seconds and shared across callers;tools/callrequests are never cached.Stripping can be disabled per request for comparison with
POST /mcp?strip_input=false&strip_output=false.POST /is an alias forPOST /mcp.
Documentation
Companion guide: how the proxy works and what each recipe does (
docs/hairpin_mcp_deployment_guide.md)Deployment inventory, IAM bindings, and verification runbook (
docs/deployment.md)
Repository structure
.
├── .env.example # Environment variable template
├── Dockerfile # Cloud Run container definition for the Hairpin MCP proxy
├── AGENTS.md # Repository coding standards (Google Python Style Guide)
├── justfile # Task runner recipes
├── pyproject.toml # Project dependencies and Pyink/Ruff/Pytype config
├── docs/
│ ├── deployment.md # Deployment inventory and verification runbook
│ └── hairpin_mcp_deployment_guide.md # Companion guide to the recipes and hairpin.py
├── src/
│ └── secops_hairpin_mcp/
│ ├── agent.py # Gemini Enterprise connector resolution & ADK agent factory
│ ├── cli.py # Typer + Rich CLI
│ ├── hairpin.py # Cloud Run Hairpin MCP proxy server
│ └── server.py # ASGI entrypoint for Cloud Run (uvicorn)
└── tests/
├── test_connectors.py # Unit tests for connector discovery and registration
└── test_hairpin.py # Unit tests for schema stripping and proxy endpointsJust recipes reference
Recipe | Description |
| Create |
| Synchronize virtual environment with lockfile |
| Deploy the Hairpin MCP proxy to Cloud Run ( |
| Configure GCP project IAM roles and Cloud Run |
| Register the Cloud Run Hairpin MCP proxy in Gemini Enterprise Discovery Engine |
| List Gemini Enterprise MCP connectors in table view |
| List MCP connectors in JSON format |
| Run the vanilla ADK agent locally against the Hairpin MCP connector |
| Deploy the vanilla ADK agent to Vertex AI Agent Engine |
| Delete the reasoning engine ( |
| Run pytest unit test suite |
| Format code in-place with Pyink (2 spaces, 80 columns) |
| Run Ruff checks and Pyink format verification |
| Run Google Pytype static type analysis |
| Remove caches, coverage reports, and build artifacts |
This server cannot be deployed
Maintenance
Related MCP Connectors
The OpenRouter for tools. One MCP connection gives any AI agent 254 hosted tools, pay per call.
Google-OAuth-gated LLM gateway: verify a Google ID token, then run a Gemini (Vertex AI) completion f
One MCP endpoint for Claude, GPT & Gemini: 100+ tools + no-code connectors + agent workers.
Unified MCP Server is a remote MCP connector for AI agents and vertical AI products that provides access to 22,000+ authorized SaaS tools across 400+ integrations and 24 categories directly inside LLMs (Claude, GPT, Gemini, Cohere). Tools operate only on explicitly authorized customer connections, enabling agents to safely read and write against live third-party systems.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceReduces LLM context window overhead by proxying multiple MCP servers through a few efficient dispatch tools instead of registering hundreds of individual tool schemas. It supports multi-account routing and tool discovery for both CLI-based and persistent MCP server configurations.MIT
- FlicenseNot gradedqualityCmaintenanceEnables MCP tool calls with strict schema validation and stdio isolation, while providing a security gateway for tool-level authorization, streaming PII redaction, and model failover routing.-
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to discover and invoke backend tools over MCP JSON-RPC while enforcing 3-legged OAuth 2.0 identity propagation, role-based access control, and protocol transcoding to REST APIs.1Apache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables an orchestrating LLM to delegate bounded text tasks and extract structured findings to a Gemini model through validated MCP tools, while keeping the bridge local and security-conscious.Apache 2.0