Memory, Gateway, and Identity, hands-on
A bare Runtime runs a loop but forgets everything between sessions, can only call tools you wired into its container, and has no way to act as the user without holding the user's secrets. Three AgentCore components fix those in turn: Memory (cross-session recall), Gateway (your APIs as MCP tools), and Identity (act-as-the-user without secrets in the prompt). Chapters 17 and 18 decoded them; this chapter shows the API shapes and a scenario each. Follow-along is illustrative, and because these are recent APIs, confirm exact field names against current docs before you deploy; the structure and the ideas are what carry.
Memory: events in, records out
AgentCore Memory splits, as the memory chapter's pipeline predicted, into a control-plane resource you create and a data-plane flow of events and retrievals. You create a memory store with one or more strategies, which are the extraction policies by another name:
# illustrative, control plane (bedrock-agentcore-control)
mem = client.create_memory(
name="hive-user-memory",
eventExpiryDuration="P90D", # raw events age out after 90 days
memoryStrategies=[
{"semanticMemoryStrategy": {"name": "facts"}},
{"userPreferenceMemoryStrategy": {"name": "prefs"}},
{"summaryMemoryStrategy": {"name": "rolling-summary"}},
],
memoryExecutionRoleArn=MEM_ROLE)
At runtime you write events (the raw conversation, short-term memory) and the strategies asynchronously distill them into memory records (the durable long-term facts):
# illustrative, data plane (bedrock-agentcore)
client.create_event(
memoryId=mem_id, actorId=user_id, sessionId=session_id,
payload=[{"conversational": {"role": "USER",
"content": {"text": "I deploy on Tuesday mornings only."}}}])
# later, in any session, retrieve what the strategies distilled:
hits = client.retrieve_memory_records(
memoryId=mem_id,
namespace=f"/strategies/prefs/actor/{user_id}",
searchCriteria={"searchQuery": "when does this user deploy?"},
maxResults=3)
The namespace is the key mechanism: strategies write records into namespaces scoped by actor (and strategy), so retrieval for one user searches only that user's records, which is tenant/user isolation enforced by the namespace path, not by a filter you must remember to add. Short-term (events) versus long-term (records) maps to the state-vs-memory distinction: events are the session transcript, records are the distilled knowledge that outlives it.
Scenario, cross-session personalization. A support copilot writes
every turn as an event under the user's actorId. Overnight, the
user-preference strategy extracts "deploys Tuesday mornings, prefers
staging first, owns the payments service" into the prefs namespace. Next
week, in a brand-new session, the agent's first act is a
retrieve_memory_records against that namespace, and it opens already
knowing the user's context, no re-interrogation. The
buying-does-not-answer caveats still bind: you
tune the strategy's extraction precision and you still owe a
memory eval, because managed extraction
still rots as it fills.
Gateway: your API becomes MCP tools
Gateway manufactures an MCP server in front of things you already have, so the MCP protocol you built by hand is what an agent speaks to reach them. You create a gateway with an inbound authorizer (who may call it) and add targets (what it exposes):
# illustrative
gw = client.create_gateway(
name="hive-tools", protocolType="MCP",
authorizerType="CUSTOM_JWT",
authorizerConfiguration={"customJWTAuthorizer": {
"discoveryUrl": "https://idp.example.com/.well-known/openid-configuration",
"allowedClients": ["hive-agents"]}},
roleArn=GW_ROLE)
client.create_gateway_target(
gatewayIdentifier=gw["gatewayId"], name="metrics-api",
targetConfiguration={"mcp": {"openApiSchema": {
"s3": {"uri": "s3://hive/schemas/metrics-openapi.json"}}}},
credentialProviderConfigurations=[{"credentialProviderType": "GATEWAY_IAM_ROLE"}])
The target types are the decoder ring's list:
a Lambda function, an OpenAPI schema (every operation becomes a
tool), or a Smithy model. Gateway returns an MCP endpoint URL; an
MCP client (a Strands agent, the runtime's agent, your
150-line client) connects to it with a bearer token and calls
tools/list then tools/call, exactly the wire the
MCP-from-scratch lab implemented.
Two SME points. Inbound versus outbound auth are different questions:
the authorizerConfiguration controls who may call the gateway (a JWT
from your IdP), while credentialProviderConfigurations controls how
the gateway authenticates to the target (its IAM role, or an OAuth
credential, or an API key). And semantic tool search solves the
discovery-economics problem: point a gateway at hundreds
of API operations and an agent would drown in tool schemas, so Gateway
offers a built-in search so the agent loads only the handful of tools a
task needs, the tool-search mitigation as a managed
feature.
Scenario, wrap an internal API. Your metrics service has an OpenAPI
spec. One create_gateway_target turns all its read operations into MCP
tools, authenticated to the service by the gateway's IAM role, and now
any MCP-speaking agent on the platform can query metrics without a
hand-written tool wrapper, and without the metrics service knowing
anything about agents. The Chapter 50 verdict holds:
Gateway earns its keep on the enterprise long tail of existing APIs,
where hand-wrapping hundreds of them is the cost you are avoiding.
Identity: act as the user, no secrets in the prompt
The deepest of the three. When an agent calls a tool that reaches a real third-party system as the user, GitHub, Google, Slack, someone's authority is exercised, and the confused-deputy failure says the agent must act as the user, with the user's tokens, which must never enter the prompt where an injection could exfiltrate them. AgentCore Identity is the managed token vault and OAuth choreography for exactly this. You register a credential provider once, then the SDK's decorators fetch tokens at the boundary:
# illustrative: the agent's tool gets a fresh user token, transparently
from bedrock_agentcore.identity.auth import requires_access_token
@requires_access_token(provider_name="google", scopes=["calendar.readonly"],
auth_flow="USER_FEDERATION") # 3-legged OAuth
def read_calendar(access_token: str, when: str) -> str:
# access_token was retrieved from the vault and injected here;
# it never appeared in the model's context.
return google_calendar_get(access_token, when)
The property that matters is the negative one the Identity chapter named: the token never transits the model. Identity runs the OAuth flow (three-legged for act-as-the-user, two-legged for act-as-the-service), stores the tokens in the vault, and injects the current one into the tool call at execution time, so a fully injected agent can misdirect what the tool is asked to do but cannot harvest what authority it carries. This is rung four applied to third-party credentials, and it is the same convergent design as Anthropic's egress substitution: credentials attach outside the agent's reach.
Scenario, the personal assistant. A copilot that schedules meetings
holds no Google tokens. The first time it needs the user's calendar,
@requires_access_token triggers the three-legged OAuth consent (the
user authorizes once), the vault stores the refresh token, and every
later call gets a fresh access token injected, with the user's own
calendar permissions and nothing more. The agent acts as Alice, sees
only Alice's calendar, and could not leak Alice's token if it tried,
because it never held it.
Don't be confused: the execution role vs Identity. Both are "how the agent authenticates," on opposite sides of a line. The execution role is the platform's identity, what the runtime container itself may do (invoke the model, read its ECR image, write logs), scoped narrow and the same for every user. Identity provides the user's delegated authority, per-user OAuth tokens fetched from the vault for third-party calls. The execution role is one identity for the container; Identity mints per-user, per-session credentials on top. Trying to make the execution role hold every user's Google token is the confused-deputy mistake with extra steps; the whole point of Identity is that it does not.
👉 Next: the rest of the stack, and the full deploy, Code Interpreter and Browser for the agent's hands, Observability, Policy, and Evaluations for watching and governing it, and the complete end-to-end deployment with a production checklist.