Skip to content
Everruns Cloud is open in early access. Run agents without operating the platform.

Serve on Amazon Bedrock AgentCore (experimental)

Experimental. Like serve, everruns-serve-agentcore is a proof of concept with no compatibility promise.

Amazon Bedrock AgentCore Runtime runs your agent container once per session, each copy in its own microVM, and talks to it over HTTP on port 8080. everruns-serve-agentcore (imported as serve_agentcore) serves that contract around a serve app, so the same app runs under dev on a laptop and on AgentCore without changes.

AgentCoreserve
Runtime session (X-Amzn-Bedrock-AgentCore-Runtime-Session-Id)One serve session: the AG-UI thread defaults to the session id
POST /invocationsAn AG-UI 1.0 run of the app’s agent, streamed as server-sent events
GET /pingHealthy, or HealthyBusy while a turn runs so AgentCore keeps the microVM up
Session storage mount (/mnt/workspace)serve’s SQLite session log and the agent’s workspace
The session microVMThe sandbox: [sandbox] kind = "microvm" gives the agent a real shell
Gateway inference target (/inference/v1)serve’s model gateway (SERVE_GATEWAY_URL)
Gateway MCP targetA #[connection] returning McpServer

serve’s /v1 wire API and /health stay mounted next to the AgentCore routes.

Start from any serve app and change main:

use serve::prelude::*;
#[tokio::main]
async fn main() -> serve::Result {
serve_agentcore::start(App::builder().discover().build()).await
}
[dependencies]
everruns-serve = { version = "0.33", features = ["ag-ui"] }
everruns-serve-agentcore = "0.33"

With no command (what AgentCore runs) or agentcore, the binary serves the AgentCore contract in serve’s start mode. Every other command (dev, start, eval, manifest, deploy) is serve’s own.

Try the contract locally with the offline simulator:

Terminal window
cargo run -p serve-example-agentcore -- agentcore --dev
curl -s localhost:8080/ping
# {"status":"Healthy"}
curl -N localhost:8080/invocations \
-H 'content-type: application/json' \
-H 'x-amzn-bedrock-agentcore-runtime-session-id: local-session-0000000000000000000000001' \
-d '{"prompt":"Where is order A-1001?"}'
# data: {"type":"RUN_STARTED",...}
# ...
# data: {"type":"RUN_FINISHED",...}

/invocations takes either an AG-UI RunAgentInput (what AgentCore’s AG-UI protocol forwards from CopilotKit or @ag-ui/client) or {"prompt": "..."} (a plain InvokeAgentRuntime call). Without a threadId and without the session header, it answers 400 with a problem document.

AgentCore runs linux/arm64 images on port 8080. The agentcore example has a distroless Dockerfile; build and push from the repository root:

Terminal window
docker buildx build --platform linux/arm64 \
-f examples/serve/agentcore/Dockerfile -t "$ECR_REPO:latest" --push .

Create the runtime with the AG-UI protocol and session storage:

Terminal window
aws bedrock-agentcore-control create-agent-runtime \
--agent-runtime-name serve_agentcore_example \
--agent-runtime-artifact "containerConfiguration={containerUri=$ECR_REPO:latest}" \
--role-arn "$EXECUTION_ROLE_ARN" \
--network-configuration networkMode=PUBLIC \
--protocol-configuration serverProtocol=AGUI \
--filesystem-configurations '[{"sessionStorage":{"mountPath":"/mnt/workspace"}}]' \
--environment-variables "SERVE_GATEWAY_URL=$GATEWAY_URL/inference/v1,SERVE_GATEWAY_KEY=$GATEWAY_TOKEN"

Use serverProtocol=HTTP instead when callers send {"prompt": ...}; /invocations accepts both either way.

From the CLI:

Terminal window
aws bedrock-agentcore invoke-agent-runtime \
--agent-runtime-arn "$AGENT_ARN" \
--runtime-session-id "$(uuidgen)-$(uuidgen)" \
--payload "$(echo -n '{"prompt":"Where is order A-1001?"}' | base64)" \
out.txt && cat out.txt

From an AG-UI client, point HttpAgent at the runtime’s invocations URL and send the session header, as the workspace example’s client does. It also shows the approval round trip: the first run ends with an interrupt outcome, and the next run resumes it.

const agent = new HttpAgent({
url: `https://bedrock-agentcore.${region}.amazonaws.com/runtimes/${encodeURIComponent(agentArn)}/invocations?qualifier=DEFAULT`,
headers: {
Authorization: `Bearer ${token}`,
"X-Amzn-Bedrock-AgentCore-Runtime-Session-Id": session,
},
threadId: session,
});

Reuse a session id to return to the same microVM, conversation and workspace.

AgentCore mounts session storage only when an invocation arrives, not while the container initializes. So /ping never touches storage, and the server boots on the first other request. It then picks, in order:

  1. SERVE_DATA_DIR (or a SQLite DATABASE_URL) when set. The workspace is SERVE_WORKSPACE, else workspace/ under the data dir.
  2. /mnt/workspace when it is mounted: the session log goes to /mnt/workspace/.serve, and the agent’s workspace is /mnt/workspace.
  3. Otherwise a temporary directory, with a warning that nothing survives the microVM stopping.

With session storage, a conversation survives AgentCore stopping the microVM after its idle timeout: the next invocation with the same session id resumes it from the log. Session storage is per session, kept for 14 days, and reset when you deploy a new runtime version. For history across sessions and versions, point DATABASE_URL at storage you own, such as an S3 Files or EFS mount (both need VPC mode).

  • In-process tools. #[tool] functions run in the container like anywhere else, including needs_approval tools: over AG-UI the run ends with a tool_approval interrupt and the client’s next run answers it.

  • A real shell. With [sandbox] kind = "microvm" in serve.toml, each agent gets bash and file tools in the session’s workspace, running directly in the container. The microVM is the isolation boundary, so there is no second sandbox inside it. Under dev and eval the same setting uses the bashkit virtual shell, so local runs stay safe. Install whatever the agent should run (git, python, a compiler) in the image, as the workspace example Dockerfile does.

  • AgentCore Gateway tools. A Gateway is an MCP server, so connect it like any other:

    #[connection]
    fn gateway() -> McpServer {
    McpServer::http("https://<gateway-id>.gateway.bedrock-agentcore.<region>.amazonaws.com/mcp")
    .auth(Secret::named("GATEWAY_TOKEN"))
    }

    start mode, which AgentCore runs, refuses to boot when GATEWAY_TOKEN is unset, so a misconfigured runtime fails its first invocation instead of running without tools.

serve routes provider/model ids through its gateway. Set SERVE_GATEWAY_URL to an AgentCore Gateway inference endpoint (https://<gateway>/inference/v1) with targets named after providers (anthropic, openai), and anthropic/claude-sonnet-5 routes as-is. Provider API keys then stay in the Gateway’s credential providers instead of the runtime’s environment.

VariableMeaning
PORTListen port, default 8080 (AgentCore requires 8080)
SERVE_AGENTCORE_AGENTThe agent /invocations runs, default the app’s default agent
SERVE_DATA_DIR, DATABASE_URLWhere the session log lives. Default: session storage when mounted
SERVE_WORKSPACEThe agent’s workspace. Default: the session storage mount
SERVE_GATEWAY_URL, SERVE_GATEWAY_KEYserve’s model gateway
serve-agentcoreStrands / bedrock-agentcore SDK
/ping, /invocations, busy reportingYesYes
AG-UI protocolYes, AG-UI 1.0 including interruptsYes
/ws WebSocketNot yetYes
MCP and A2A server protocolsNot yetYes
Conversation persistenceSQLite on session storageFile or AgentCore Memory session managers
Long-term memory (AgentCore Memory)Not yetYes
Gateway toolsMCP connectionMCP client
Shell and filesBuilt-in (sandbox = "microvm")Bring your own tools
Code Interpreter, BrowserNot yetClient libraries
Identity (OAuth to third parties)Secrets from the environment@requires_access_token
Offline evals and simulatorYes (eval, --dev)No
  • Approvals and ask_user questions park a turn without keeping the microVM busy, and a parked turn does not survive a restart yet. Answer within the idle timeout (15 minutes by default).
  • #[schedule]s run in-process, so they only fire while a session’s microVM is up. Use EventBridge to call InvokeAgentRuntime on a schedule instead.
  • The Bedrock model driver takes static keys only. Route models through an AgentCore Gateway, or another gateway, rather than relying on the runtime’s IAM role.