An agent that answers correctly on a developer’s machine still needs a controlled path to its tools, users and serving revision. This guide is for the developer and cloud owner who already has an authorized Google Agent Development Kit (ADK) agent, a real task contract, an API-key-protected Streamable HTTP MCP server, and an internal application ingress that authenticates callers and owns their sessions. The outcome is either one reviewed Agent Runtime revision serving those users or a recorded hold at the failed check. The steps follow Google’s documentation checked on 22 October 2026; BIG CHANGE did not run a reader’s agent, cloud project or security test.
The big change
- What changed: Google’s Agent Runtime can host an ADK agent as a managed
reasoningEngine, with Agent Identity credentials for its outbound tool and active revisions for controlled traffic. - Why it matters: The tool’s API key identifies the agent to the MCP server. It does not establish which person submitted a request. An authenticated ingress and protected session-owner record have to make that decision before the agent runs.
- What to watch: Offline evaluation needs approved content-bearing traces. “Always latest” traffic can expose an updated revision before review, while an archived revision cannot be restored.
1. Fix the task and release inputs
Write down one actual user task, its inputs, acceptable answer, permitted MCP action and observable side effect. Include a malformed request, a denied user, another user’s session, a tool failure and the rule for when a person must intervene. Save the agent source commit, model ID, prompt, tool names/schema and endpoint, resolved Python dependencies, test fixtures, data classification, expected latency and cost threshold. These are the release record against which the deployed candidate will be checked; the example exchange-rate agent in Google’s ADK quickstart is not a test of your task.
The following names must be replaced with values from the owner’s approved staging environment: PROJECT_ID, PROJECT_NUMBER, ORGANIZATION_ID, supported LOCATION, STAGING_BUCKET, AUTH_PROVIDER_NAME, ENGINE_ID, full engine RESOURCE_NAME, returned CANDIDATE_REVISION_ID, Cloud Run SERVICE_NAME, approved staging user and task input, your existing ADK agent settings and tools, and the authorized MCP_URL. Use separate staging data and principals. Confirm billing, region support, Agent Platform, Agent Identity and Cloud Storage APIs, deployment permissions, and the authority to issue the MCP key. An OAuth-only endpoint needs a different authentication route. Do not place the key in agent source, prompts, logs or the release record. Google’s Runtime setup and API-key auth guide specify the account and role checks.
The ingress is also a prerequisite, not code supplied by Agent Runtime: this internal route uses an already enforced Cloud Run service protected by IAP and a reader-owned, protected mapping from a verified IAP subject to an ADK user_id and owned session_id. If that adapter and store do not exist or cannot be checked, hold the multi-user release.
2. Establish an agent identity, then deploy the authenticated candidate
From the owned agent project, first run its existing local tests and owner-authored ADK task cases. Record the observed outputs and real MCP effects. The quickstart shows local AdkApp.async_stream_query; its local sessions are in memory. Authenticate the authorized deployment operator with gcloud auth application-default login, use a project and region confirmed for this account, and resolve and lock compatible versions of google-cloud-agentplatform[adk]==2.4.0 and google-adk[agent-identity,mcp]>=2.7.1. The pinned package’s PyPI metadata lists adk as an extra; runtimes is the client namespace, not an extra in that release. Keep the exact resolved versions in the release record. This procedure uses the standalone agentplatform.Client surface for both create and update. Google’s SDK migration guide maps the older vertexai interface to client.runtimes; the pinned 2.4.0 ADK wrapper source exposes set_up() and preserves subclasses in clone(), which matters for provider registration in the deployed app. The commands and snippets below were not executed for this article.
Agent Identity’s provider binding needs the deployed agent’s actual engine ID. If there is no existing engine, make an access-restricted baseline deployment of the reviewed agent without the outbound MCP tool, with identity_type=AGENT_IDENTITY. The current Agent Identity guide documents this agentplatform pattern from the agent project’s deployment script:
import agentplatform
from agentplatform import types
from agentplatform.frameworks import AdkApp
client = agentplatform.Client(project="PROJECT_ID", location="LOCATION",
http_options={"api_version": "v1beta1"})
baseline_app = AdkApp(agent=restricted_agent) # Owner's reviewed agent, without the MCP tool.
baseline = client.runtimes.create(
agent=baseline_app,
config={
"requirements": ["google-cloud-agentplatform[adk]==2.4.0"],
"staging_bucket": "gs://STAGING_BUCKET",
"identity_type": types.IdentityType.AGENT_IDENTITY,
},
)
baseline_readback = client.runtimes.get(name=baseline.api_resource.name)
print(baseline_readback.api_resource.name)
print(baseline_readback.api_resource.spec.effective_identity)Replace restricted_agent with the owner’s actual reviewed ADK agent in the restricted configuration and STAGING_BUCKET with an existing approved bucket name. Record and read back the returned projects/PROJECT_ID/locations/LOCATION/reasoningEngines/ENGINE_ID and its spec.effective_identity principal. Keep this baseline unavailable to end users. A submitted create request alone is not a completed deployment. For an existing engine, use the same v1beta1 client and its full name before using the engine ID below:
existing = client.runtimes.get(name="RESOURCE_NAME")
print(existing.api_resource.name)
print(existing.api_resource.spec.effective_identity)Confirm that the returned principal identifies this exact engine and project as an Agent Identity principal. If it is missing, belongs to another engine or instead uses a service account, stop: the identity flag in the new-engine example does not change an existing engine. Have the owner review a separate identity-enabled resource and its traffic/session migration before continuing. The identity guide documents the effective-identity readback and an identity-only bootstrap.
In the Google Cloud console, open Agent Registry → your agent → Identity → Add auth provider, choose API key, supply the server-issued key in the provider credential control, and grant the deployed agent access. The current Agent Identity API-key guide documents the equivalent CLI but putting --api-key in a shell command risks exposing it in history or process records. Read back an ENABLED provider at projects/PROJECT_ID/locations/LOCATION/authProviders/AUTH_PROVIDER_NAME. Provider creation requires agentidentity.authProviders.create (the documented Agent Identity Admin or Editor roles); use requires agentidentity.authProviders.retrieveCredentials and the documented Agent Identity User, Vertex AI User and Service Usage Consumer permissions. For an administrator who grants the agent explicitly, Google documents this binding, with the real organization/project numbers and returned engine ID:
gcloud agent-identity auth-providers add-iam-policy-binding AUTH_PROVIDER_NAME \
--project="PROJECT_ID" --location="LOCATION" \
--role="roles/agentidentity.user" \
--member="principal://agents.global.org-ORGANIZATION_ID.system.id.goog/resources/aiplatform/projects/PROJECT_NUMBER/locations/LOCATION/reasoningEngines/ENGINE_ID"
gcloud agent-identity auth-providers list --project="PROJECT_ID" --location="LOCATION"Use the verified effective_identity principal exactly in that binding; the shown agents.global.org-... form applies to an organization-backed project, while Google documents a proj-... trust domain for a project without an organization. Check the provider IAM binding and ENABLED state in fresh readbacks rather than assuming the console click or CLI request took effect.
Now prepare the tool-enabled source. In the agent project’s reviewed deployment script, put the direct MCP toolset in the actual root agent’s tools list before constructing the app. The example constructor below shows that attachment; fill its capitalized inputs from the existing reviewed agent and preserve any other settings, callbacks and subagents in that agent’s real constructor. OWNED_APPROVED_TOOLS is its existing approved tool list, not a new tool grant. The direct MCP route uses the v2 authProviders name:
import agentplatform
from agentplatform.frameworks import AdkApp
from google.adk.agents import Agent
from google.adk.auth.credential_manager import CredentialManager
from google.adk.integrations.agent_identity import GcpAuthProvider, GcpAuthProviderScheme
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
from google.adk.tools.mcp_tool.mcp_toolset import McpToolset
auth_scheme = GcpAuthProviderScheme(
name="projects/PROJECT_ID/locations/LOCATION/authProviders/AUTH_PROVIDER_NAME"
)
approved_mcp = McpToolset(
connection_params=StreamableHTTPConnectionParams(url="MCP_URL"),
auth_scheme=auth_scheme,
)
agent = Agent(
name=OWNED_AGENT_NAME,
model=OWNED_MODEL,
instruction=OWNED_PROMPT,
tools=[*OWNED_APPROVED_TOOLS, approved_mcp],
)
class AuthenticatedAdkApp(AdkApp):
def set_up(self):
CredentialManager.register_auth_provider(GcpAuthProvider())
super().set_up()
app = AuthenticatedAdkApp(agent=agent)
client = agentplatform.Client(
project="PROJECT_ID", location="LOCATION",
http_options={"api_version": "v1beta1"},
)Google’s API-key guide illustrates registration in set_up() with its older Vertex wrapper because module-level registration in the local script does not run inside the serialized deployment. The current Agent Platform 2.4.0 wrapper source retains that hook and its subclass when cloned for deployment. Do not combine this direct McpToolset route with an Agent Registry outbound binding or a three-legged OAuth example.
Before updating the restricted engine, approve the content-bearing staging fixtures, Cloud Trace viewers, evaluation output bucket, region and retention described in step 4. The candidate update below enables remote content capture; a local shell environment variable would not configure its container. Use Govern → Deployments → Revisions → Manage traffic to select a manual 100% split to the active baseline revision and read it back. Google’s revision guide says root-resource requests otherwise default to the latest revision, including a newly created one. Then update the same engine with the reviewed AuthenticatedAdkApp and requirements. In the same deployment script as the agentplatform.Client and app above, replace RESOURCE_NAME with the returned full engine name:
updated = client.runtimes.update(
name="RESOURCE_NAME",
agent=app,
config={
"staging_bucket": "gs://STAGING_BUCKET",
"requirements": [
"google-cloud-agentplatform[adk]==2.4.0",
"google-adk[agent-identity,mcp]>=2.7.1",
],
"env_vars": {
"GOOGLE_CLOUD_AGENT_ENGINE_ENABLE_TELEMETRY": "true",
"OTEL_SEMCONV_STABILITY_OPT_IN": "gen_ai_latest_experimental",
"OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT": "EVENT_ONLY",
},
},
)
print(updated.api_resource.name)The current manage-deployed-agents manual documents client.runtimes.update(name=..., agent=..., config=...); the deployment manual documents remote env_vars in that deployment config, and the tracing manual gives those three remote ADK settings. Set them only after staging content capture, viewers and retention are approved. Do not infer an update from editing local code. Wait for the operation, list the engine’s runtime revisions, and record the newly returned active candidate revision and its source/dependency identifiers. Keep root traffic on the prior active revision while the candidate is checked. If the exact SDK version or deployment fails, inspect the operation and repair that specific failure before another update.
Target the candidate explicitly for staging checks. While the root engine remains manually pinned to the baseline, remote_agent.async_stream_query on that root tests the baseline. Google’s revision traffic guide says a direct request to an ACTIVE revision bypasses the root split. Its v1beta1 revision stream method, combined with the documented ADK stream request, gives this authorized staging-operator check. Run it with an owner-approved fixture after replacing the revision ID and task values:
curl -N -H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
"https://LOCATION-aiplatform.googleapis.com/v1beta1/projects/PROJECT_ID/locations/LOCATION/reasoningEngines/ENGINE_ID/runtimeRevisions/CANDIDATE_REVISION_ID:streamQuery?alt=sse" \
-d '{"class_method":"async_stream_query","input":{"user_id":"STAGING_USER_ID","message":"OWNER_APPROVED_TEST_INPUT"}}'Add the owner-approved session_id inside input when checking an existing session. The staging operator needs the revision-query permission; Google notes that revision query and root query are distinct grants. Record the addressed full revision name and returned tool events. To test user isolation through the ingress on this candidate, the reader’s existing staging adapter must target that same revision path with its service account’s narrowly scoped revision-query permission while retaining its signed-IAP and session-owner checks. If the adapter only calls the root engine and cannot select a revision, it has tested the baseline; hold candidate approval until it can target the revision or an equivalent isolated staging route is reviewed. Never give end users direct revision access.
3. Bind each caller to a session outside Runtime
For this internal route, IAP protects the existing Cloud Run ingress. On every request, that application verifies x-goog-iap-jwt-assertion: Google’s signing key and signature, issuer, Cloud Run audience /projects/PROJECT_NUMBER/locations/LOCATION/services/SERVICE_NAME, iat and exp. Derive the stable caller from the verified sub claim. The IAP signed-header instructions and Cloud Run IAP setup govern the precise verifier and audience. An email header or a client-provided user_id is not proof of identity.
The existing adapter authorizes that subject for the task, maps it server-side to the ADK user_id, and creates or checks an owner-to-session_id binding in its protected store. It rejects a supplied session ID unless the stored owner is the verified subject before calling the reviewed runtime operation with server-derived user_id and approved session_id. Grant only the ingress service account a narrow aiplatform.reasoningEngines.query permission on this engine for root serving; its restricted staging revision target needs the separate revision-query permission described above. End users receive no direct Runtime, revision-query or Session API roles. Google’s agent-sharing guide treats a trusted frontend as responsible for user and session IDs; Runtime’s user_id string does not authenticate a caller. Session IAM Conditions can restrict certain direct session methods but do not cover ListSessions, so an unconditional listing grant cannot be described as per-user isolation.
Test the actual adapter with two allowed subjects and one denied subject. Try a forged user_id, the other subject’s session_id, missing/tampered/expired/wrong-audience IAP JWTs, and direct Runtime query and Session get/list calls as an end user. Each bypass must fail without another user’s content or a tool effect. For permitted and denied MCP actions, check the server’s actual side-effect record, not just the agent’s prose. Any cross-user access or unintended action holds the release; fix the ingress/store or IAM grant and repeat the negative checks.
4. Evaluate the task with approved staging content
Run the owner’s normal, denied, malformed and tool-failure cases against the tool-enabled candidate revision, then inspect the results and tool records. The staging approvals made before deployment cover inputs, outputs, system instructions and tool definitions. The candidate deployment config in step 2 sets these variables inside the remote container, with Cloud Trace enabled:
OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental
OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=EVENT_ONLYRead back the candidate deployment’s env_vars and check the emitted invoke span for gen_ai.agent.name, gen_ai.agent.description and gen_ai.conversation.id; the gen_ai.client.inference.operation.details event must contain gen_ai.input.messages, gen_ai.output.messages, gen_ai.system_instructions and gen_ai.tool.definitions. The offline evaluation manual requires this content-bearing context. In Agent Platform → Agents → Evaluation, select the approved Trace or Session IDs, output bucket and suitable metrics, run the evaluation, then inspect its actual result beside the owner’s task and side-effect checks. A generic grade alone cannot prove isolation or permission control. If policy forbids that content capture, or the required events are absent, mark this offline route held, not run with NO_CONTENT and not passed. Local tests and human acceptance remain separate. Repeat the affected checks after any source, model, prompt, tool or policy change.
5. Review cost, activate traffic and keep a recovery route
Read back trace and bucket access, retention, model/Runtime/MCP/Cloud Run/IAP/logging/evaluation prices, quotas and actual bills in the owner’s account. Quotas limit some request rates; they are not budgets. Billing alerts warn. Google’s eligible spend cap can pause new usage for a supported service in one project and month on eligible first-party accounts, but enforcement has lag, in-flight requests complete and fixed resources keep charging. It does not cap the entire agent stack. Record the person who can stop ingress traffic and the cost threshold that triggers action.
The owner approves the exact source commit, prompt/model/dependency lock, provider and MCP permissions, ingress identity contract, tests, trace access, cost limits and candidate revision. List its state and the known-good revision with the v1beta1 revision REST GET: https://LOCATION-aiplatform.googleapis.com/v1beta1/projects/PROJECT_ID/locations/LOCATION/reasoningEngines/ENGINE_ID/runtimeRevisions. Only ACTIVE revisions can receive a manual split. After targeted candidate tests and approval, set a deliberate split in Manage traffic or use that page’s reasoningEngines.patch at ...?update_mask=traffic_config, with trafficConfig.trafficSplitManual.targets naming full active revision resources and integer percentages totaling 100. Wait for the operation and read back the serving split; submitting a patch is not activation proof. Query through the ingress as allowed and denied callers after each widening step. Check actual serving revision, tool effects, errors, latency, token use, traces and bills against the release record.
On a failure, stop or reduce new traffic under the owner’s policy and direct traffic to an active reviewed revision. Preserve the request, denial, tool, trace, evaluation and cost evidence. An archived revision cannot be restored. Google warns that attaching, changing or detaching an Agent Gateway binding archives every older revision; if that has removed the known-good active revision, redeploy equivalent reviewed source and rerun the identity, tool and task checks before serving it. A new green deployment alone does not complete recovery.
The release record is complete when the actual engine and active serving revision match the approved source and dependencies; two permitted and one denied identity have the expected session and tool outcomes; the owner’s task checks and the selected content-bearing offline evaluation have inspected results; privacy and all-service spending controls have readbacks; and an active known-good route exists. If staging content capture is prohibited, hold this offline-evaluation release route until the owner approves another supported evaluation path. Record any other failed gate and keep the release held. This is a documentation-based procedure, not a report that those checks passed in any particular project.
Sources & further reading
- Deploy an agent —
client.runtimes.createconfiguration, including remoteenv_vars; it does not prove a reader’s deployment completed. - ADK Agent Runtime quickstart — local ADK task-check pattern; its sample task is not this reader’s acceptance test.
- Use Agent Identity with Agent Runtime — v1beta1
agentplatformcreate, effective-identity readback and principal shape; an existing engine needs its own readback. - Agent Platform 2.4.0 ADK wrapper source — pinned
AdkApp.set_up()and subclass-preservingclone()implementation; it is SDK source evidence, not a report of execution. - Agent Platform 2.4.0 package metadata — identifies the supported
adkextra and its dependencies; no SDK install or compatibility test was run for this article. - Authenticate using an API key with auth manager — current
authProviders, SPIFFE grant, direct MCP toolset, dependencies and SDKset_up()rule; it authenticates the agent’s outbound call, not an end user. - Manage deployed agents — source update interface and metrics; an update needs a completed operation and revision readback.
- Agent Runtime SDK migration — maps the deprecated
vertexainamespace to the standaloneagentplatformcreate/update route used here. - Set up tracing —
env_varsfor the deployed ADK container, including telemetry and content capture; approval must precede capture. - Share an agent — per-agent query permission and trusted frontend responsibility for users and sessions.
- Cloud Run with IAP — internal ingress protection; it does not create the application’s session-owner store.
- IAP signed headers — JWT verification and Cloud Run audience; the guide must be applied to the actual service and verifier.
- Getting the user’s identity — IAP identity fields; use verified claims rather than trusting a user-supplied ID.
- Session IAM Conditions — supported session restrictions and the
ListSessionslimitation. - Use an ADK agent — managed sessions and remote query interfaces;
user_idremains an application choice. - Run offline evaluations — required content-bearing telemetry, selection and output storage; it does not certify this reader’s behavior.
- Manage revisions and traffic — pre-GA active revisions, manual traffic and irreversible archive effects.
- Revision streamQuery REST method — exact revision endpoint and input/class method shape; owner values and response must be verified against the returned active candidate.
- Manage spend cap budgets — eligible service scope and delayed enforcement; not an all-service ceiling.
- Agent Platform quotas — service limits to check alongside, not in place of, real billing.



