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.