Skip to content

How to maintain session state across HTTP requests in Bedrock AgentCore Runtime for MCP servers?

0

I'm deploying a Model Context Protocol (MCP) server on AWS Bedrock AgentCore Runtime and encountering issues with session state management. Each HTTP request appears to route to a different container instance, breaking the stateful nature of the MCP protocol.

Environment

  • Service: AWS Bedrock AgentCore Runtime
  • Region: ap-southeast-2
  • Protocol: MCP (Model Context Protocol) 2024-11-05
  • Transport: HTTP (streamable-http)
  • Deployment: CDK with custom container image

The Problem

The MCP protocol requires stateful interactions:

  1. Client sends initialize request to establish session context
  2. Client sends subsequent requests (tools/list, tools/call, etc.) that depend on the initialized session
  3. Session state must persist across multiple HTTP requests

However, I'm observing that each HTTP request creates a new container instance or routes to a different one:

First Request (initialize) - Succeeds:

Log Stream: [runtime-logs]b0466b0d-e887-40a2-8bf3-3d5a35787c97
Created new transport with session ID: 6735784a7e7a48249240661a1b876459
POST /mcp HTTP/1.1" 200 OK

Second Request (tools/list) - Different Container:

Log Stream: [runtime-logs]1f653e64-112b-4bff-8c66-cde58496117a
Created new transport with session ID: 0f61720e64674a42b94da78b627a73cc
POST /mcp HTTP/1.1" 400 Bad Request

The different log stream IDs indicate different container instances handling each request.

What I've Tried

1. Lifecycle Configuration

lifecycleConfiguration: {
  idleRuntimeSessionTimeout: core.Duration.hours(8)
}

Result: No change - still creates new containers per request

2. Request Header Allowlist

requestHeaderConfiguration: {
  requestHeaderAllowlist: ['X-Amzn-Bedrock-AgentCore-Runtime-Custom-Session-ID']
}

Result: Headers pass through but container still creates new sessions

3. Session ID Management

Modified my test script to capture session ID from the first response and include it in subsequent requests.

Result: Container ignores the session ID and creates a new session anyway

My Questions

  1. Does AgentCore Runtime support session affinity for HTTP requests? Can I configure it to ensure sequential requests from the same client route to the same container instance?

  2. What's the recommended pattern for stateful protocols on AgentCore? Should I be using external state storage (DynamoDB, ElastiCache) instead of relying on in-container state?

  3. How long do container instances stay alive? Does idleRuntimeSessionTimeout apply to HTTP-based runtimes? Are containers terminated immediately after each request?

  4. Is there a way to maintain session context? Are there other mechanisms I'm missing for maintaining state between HTTP requests?

CDK Configuration

const mcpRuntime = new agentCore.Runtime(this, 'mcp-runtime', {
  agentRuntimeName: 'MyMCPServer',
  protocol: agentCore.Protocol.MCP,
  artifactConfiguration: {
    containerConfiguration: {
      containerUri: 'my-ecr-repo/mcp-server:latest',
    },
  },
  authorizerConfiguration: {
    customJwtAuthorizer: {
      allowedClients: clientIds,
      discoveryUrl: cognitoDiscoveryUrl
    }
  },
  lifecycleConfiguration: {
    idleRuntimeSessionTimeout: core.Duration.hours(8),
  },
  environmentVariables: {
    // MCP server configuration
  }
});

Test Sequence

# 1. Get OAuth token
TOKEN=$(curl -X POST "$COGNITO_TOKEN_URL" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d "grant_type=client_credentials" | jq -r '.access_token')

# 2. Initialize MCP session
curl -X POST "$RUNTIME_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}'
# Returns: SUCCESS with server info

# 3. Call tools/list
curl -X POST "$RUNTIME_URL" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# Returns: ERROR {"code": -32603, "message": "An internal error occurred"}

Additional Context

  • The MCP server works correctly with stdio/WebSocket transports in local testing
  • This issue is specific to AgentCore's HTTP request routing
  • MCP Protocol Reference: https://spec.modelcontextprotocol.io/

What I'm Looking For

  • Confirmation on whether AgentCore supports stateful HTTP protocols
  • Guidance on the recommended architecture for maintaining session state
  • Examples of stateful protocol implementations on AgentCore
  • Alternative approaches if session affinity isn't supported

Has anyone successfully deployed stateful protocols on Bedrock AgentCore Runtime? Any insights would be greatly appreciated!

4 Answers
0

When working with MCP servers in Amazon Bedrock AgentCore Runtime, session state management is handled through specific mechanisms designed for stateless environments.

The key to maintaining session state across HTTP requests is using the built-in session management capabilities of AgentCore Runtime. Here's how it works:

  1. Session ID Management: AgentCore Runtime automatically adds an Mcp-Session-Id header to any request that doesn't include one. This header allows MCP clients to maintain connection continuity to the same AgentCore Runtime session.

  2. Runtime Session ID: When invoking an agent through the InvokeAgentRuntime operation, you should use the runtimeSessionId parameter. By providing the same session identifier across multiple requests, you can maintain conversation context, allowing the agent to reference previous interactions.

  3. External State Storage: Since AgentCore Runtime provides session isolation by default and requires stateless streamable-HTTP servers, you should externalize your agent state. This means persisting state after each interaction and restoring it before the next one.

For your specific implementation:

  • Make sure your MCP server is truly stateless and relies on the session identifiers provided by AgentCore Runtime rather than in-memory state.
  • Use the runtimeSessionId parameter consistently across your requests to maintain session context.
  • Consider implementing external state storage using AgentCore Memory, which is specifically designed to maintain session context using its short-term memory capabilities.

To implement AgentCore Memory:

from bedrock_agentcore.memory import MemoryClient

memory_client = MemoryClient(region_name="us-east-1")

memory = memory_client.create_memory_and_wait(
name="YourMemoryStore", 
description="Your session descriptions",
strategies=[]
)

This approach will allow your MCP server to maintain session state across multiple HTTP requests, even when different container instances handle those requests.
Sources
Invoke an AgentCore Runtime agent - Amazon Bedrock AgentCore
Introducing Amazon Bedrock AgentCore: Securely deploy and operate AI agents at any scale (preview) | AWS News Blog
Deploy MCP servers in AgentCore Runtime - Amazon Bedrock AgentCore
Amazon Bedrock AgentCore Runtime for AWS Marketplace - AWS Marketplace
Effectively building AI agents on AWS Serverless | AWS Compute Blog

answered a year ago

0

AgentCore Runtime routes requests based on the mcp-session-id header value. Different session ids will be served by different containers to ensure session isolation. The same session id will be served by the same container for the lifetime of the container. A container will be recycled after 15 min of inactivity and cannot last longer than 8hrs. If you need to persist data for longer than 8hrs you need to consider some external persistency, like DynamoDB.

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-mcp-protocol-contract.html

If you do not specify an mcp-session-id header in your invocation, AgentCore will generate one.

AWS
EXPERT

answered 10 months ago

0

https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/gateway-sessions.html

Hope the above helps "Stateful MCP server target interactions" should answer the issue.

answered 4 months ago

-1

The challenge here is that MCP session state cannot safely live inside a single runtime container in AgentCore Runtime. AgentCore does not guarantee sticky routing of HTTP requests to a particular container instance. AWS explicitly requires MCP servers running under AgentCore to be stateless between HTTP requests, which means you can’t rely on process-local RAM for protocol-level state.

If your MCP implementation requires persistent session state (not all do), that state must live somewhere external and consistent — e.g., AgentCore Memory, DynamoDB, S3, Redis, etc. That’s the only way to ensure correctness when the runtime container is replaced, scaled, or recycled.

AgentCore will horizontally scale by launching multiple runtime instances. And yes, there is session affinity: if AgentCore spins up three instances, runtimeSessionId = 1234 will usually stay pinned to “Runtime A” for as long as that session exists — up until the microVM hits its maxLifetime or idleRuntimeSessionTimeout. But you have no guarantee when AgentCore will tear down or restart that instance, so you cannot rely on in-RAM state for a “stateful MCP” design. It’s an optimization only, not a correctness mechanism.

This is different from the process-level persistence you get inside a single running agent instance. For example, in Lambda I often use a statically scoped module-level variable as a lightweight cache for data that rarely changes (like a DynamoDB read). If the Lambda is “warm,” that cache survives between invocations and saves a round-trip. But that behavior is only a best-effort optimization — scaling events, cold starts, and timeouts all wipe that state out unpredictably.

AgentCore runtimes appear to have a similar cold/warm dynamic (a microVM stays alive for the duration of a session until idle timeout or maxLifetime), but even if you did rely on process-local caching there, it wouldn’t solve the underlying MCP issue. MCP requires consistent session state, and process-level RAM inside a single runtime instance is never durable or reliable enough for that — especially given horizontal scaling and runtime recycling.

Finally, using an ECR-based agent doesn’t change these semantics. You get the same lifecycle rules, the same per-session microVM isolation, and the same requirement to externalize MCP state if you need persistence.

I hope that helps. I am not the expert, and I don't work for AWS, but sometimes I don't like how the bot answers and I have been dancing around this issue as well, so I thought maybe I could help with your question.

answered a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.