Skip to content

Building a governed incident response agent fleet with AWS Agent Registry

7 minute read
Content level: Advanced
0

AWS Agent Registry is now generally available, but most teams meet it mid-sprawl: dozens of agents and MCP tools scattered across accounts, with no shared inventory, no cross-team discovery, and no audit trail. This how-to walks operations teams through one concrete AIOps use case, governing an incident response fleet, from creating a gated registry and registering tools to catching shadow agents and discovering tools at runtime.

Most operations teams do not have an agent problem. They have an agent sprawl problem.

It starts well. One team writes an agent that reads Amazon CloudWatch alarms and drafts an incident summary. Another builds a Model Context Protocol (MCP) server that restarts unhealthy tasks. A third wraps the runbook for a noisy microservice into a small agent so the on-call engineer stops getting paged at 3 a.m. Six months later there are forty of these across a dozen accounts. Nobody has the full list. Two of them do almost the same thing. One quietly gained permission to terminate instances, and no one can say who approved that or when.

This is what AWS Agent Registry is built for. It is a centralized, searchable, and governed catalog for the agents, tools, and skills running across your organization. In this post we use it to bring an incident response fleet under control: register the agents and tools that on-call engineers rely on, put an approval gate in front of anything that can touch production, catch the ones nobody registered, and let an orchestrator agent find the right tool at runtime instead of hard-coding it.

What the Registry gives an operations team

The Registry separates two concerns that ops teams usually tangle together. The governance plane is the authoritative store of every record, in any state, where administrators configure approval workflows, discovery authorization, and metadata. The discovery plane is the curated view that consumers see, containing only approved records, with natural-language search on top.

Five record types cover the fleet: MCP for tool servers, AGENT for agents described by an A2A agent card, SKILL for reusable runbook logic, GATEWAY for AgentCore Gateway targets, and CUSTOM for anything else you describe as JSON. Every state change is written to AWS CloudTrail, so the question "who approved the terminate-instance tool, and when?" finally has an answer.

Step 1: Create the registry with a real approval gate

Start with a single registry scoped to the operations organization. Leaving auto-approval off is the point of the exercise: when no auto-approval rule is set, every submitted record waits for review, which is what you want in front of a tool that can act on production. Setting autoApprovalRules to ["APPROVE_ALL"] would approve on submission instead, which suits a sandbox but not the fleet that pages your engineers.

import boto3, json

control = boto3.client("agent-registry-control", region_name="us-east-1")
data    = boto3.client("agent-registry", region_name="us-east-1")

# No autoApprovalRules => submitted records require manual review (the gate).
registry_arn = control.create_registry(name="ops-incident-response")["registryArn"]
registry_id  = registry_arn.rsplit("/", 1)[-1]

Step 2: Register a remediation tool and a triage agent

A publisher, usually a CI/CD pipeline rather than a person, creates a record for each capability. The MCP server that performs safe restarts goes in as an MCP record. The descriptor content is the MCP server definition, serialized into data, validated against the schema named in dataSchemaVersion.

server_card = {
    "name": "io.ops/ecs-safe-restart",
    "description": "Restarts unhealthy ECS tasks with rate limiting",
    "version": "1.0.0",
}
record = control.create_registry_record(
    registryId=registry_id,
    name="ecs-safe-restart",
    displayName="ECS Safe Restart",
    recordType="MCP",
    recordVersion="1.0",
    descriptors={
        "mcpServer": {
            "data": json.dumps(server_card),
            "dataSchemaVersion": "2025-07-09",
        }
    },
)
record_id = record["recordArn"].rsplit("/", 1)[-1]

The triage agent is an AGENT record whose descriptor is its A2A agent card (schema version 0.3). The card is the same one the agent already serves, so publishing is mostly a matter of pointing the Registry at it.

agent_card = {
    "name": "incident-triage",
    "description": "Correlates alarms, ranks likely causes, drafts a summary",
    "url": "https://triage.internal.example.com/a2a",
    "version": "1.0.0",
    "capabilities": {},
    "defaultInputModes": ["text/plain"],
    "defaultOutputModes": ["text/plain"],
    "skills": [],
}
control.create_registry_record(
    registryId=registry_id,
    name="incident-triage",
    recordType="AGENT",
    recordVersion="1.0",
    descriptors={
        "a2aAgentCard": {
            "data": json.dumps(agent_card),
            "dataSchemaVersion": "0.3",
        }
    },
)

Each record is created asynchronously: it returns with status CREATING and settles to DRAFT. Once it is DRAFT, the pipeline submits it for review.

control.submit_registry_record_for_approval(
    registryId=registry_id,
    recordId=record_id,
)

Because this registry has no auto-approval rule, the record moves to PENDING_APPROVAL, and nothing about it reaches the discovery plane yet.

Step 3: Wire the approval gate to a security check

The Registry does not ship an opinion about what a good review is, because your bar for a tool that can terminate instances is not the same as your bar for one that reads logs. Instead it emits events you build on. Every state change publishes to the default Amazon EventBridge bus in the resource's own account, from source aws.agent-registry, with detail carrying registryRecordId and registryId.

Route the pending-approval event to an AWS Lambda function that runs your checks before a curator looks at it.

{
  "source": ["aws.agent-registry"],
  "detail-type": ["Registry Record State changed to Pending Approval"],
  "detail": { "registryId": ["<registryId>"] }
}

The target function reads the record, runs whatever your organization requires (a duplicate check against existing records, a scan of the tool's declared permissions, a lookup of the owning team), and records the decision. A record that fails the automated checks is rejected without human time spent; one that passes is approved.

control.update_registry_record_status(
    registryId=registry_id,
    recordId=record_id,
    status="REJECTED",   # or "APPROVED"
    statusReason="Requests iam:* with no scoping; resubmit with least privilege",
)

Approved records enter the discovery plane. Rejected ones go back to the publisher with a reason, and a fixed version can be resubmitted. The lifecycle is small enough to keep in your head: DRAFT to PENDING_APPROVAL to APPROVED or REJECTED, with DEPRECATED for retirement.

Step 4: Find the agents nobody registered

The forty scattered agents from the opening are the real test. You cannot govern what you cannot see. Turn on auto-detection when you create the registry, and it is populated with agents and MCP servers already running on Amazon Bedrock AgentCore Runtime and AgentCore Gateway across the accounts in scope.

control.create_registry(
    name="ops-detected",
    autoDetectionConfiguration={"enabled": True, "scope": "ORGANIZATION"},
)

Detected resources arrive as draft records and then follow the same lifecycle as everything else. New agents in connected accounts show up on their own, with no action from the team that built them. Shadow AI turns into a queue you can work through instead of a blind spot.

Step 5: Discover tools at runtime instead of hard-coding them

This is where the catalog earns its place during an incident. The data plane exposes natural-language search, so an orchestrator agent can ask for a capability in words and get back approved, governed options rather than a hard-coded list that goes stale. registryIds takes exactly one registry, and only APPROVED records come back.

results = data.search_discoverable_registry_records(
    registryIds=[registry_id],
    searchQuery="restart an unhealthy ECS service safely",
    maxResults=5,
)

The same registry is also reachable as an MCP server, so an MCP-compatible IDE such as Kiro or Claude Code can query it directly. An engineer types "find me a tool that rotates database credentials" and gets results from the governed catalog. For a JWT-auth registry, connection uses Dynamic Client Registration, so the client negotiates trust at runtime and the engineer authenticates once through the organization's identity provider. For an IAM-auth registry, the endpoint is called with SigV4 (action agent-registry:InvokeRegistryMcp). The endpoint exposes three discovery tools: search_discoverable_registry_records, list_discoverable_registry_records, and batch_get_discoverable_registry_record.

https://agent-registry.<region>.api.aws/registry/<registryId>/mcp

Closing the loop: designed behavior versus actual behavior

Registration records what an agent is meant to do. Pairing that with AgentCore Observability, which emits traces in OpenTelemetry format, and AgentCore Policy, which evaluates every tool call at the Gateway perimeter, lets you compare the two. The Registry says the restart tool is allowed to restart tasks. The traces show what it actually called. When those diverge, you have the record, the version, and the owner in one place.

Getting started

AWS Agent Registry is generally available with consumption-based pricing and a free tier. New to the service? Start with the launch blog for the concepts, then the AWS Agent Registry Developer Guide and the API Reference for the request shapes behind each record type.