![[アップデート]AWS Agent Registryが一般提供開始されました!](https://images.ctfassets.net/ct0aopd36mqt/7M0d5bjsd0K4Et30cVFvB6/5b2095750cc8bf73f04f63ed0d4b3546/AgentCore2.png?w=3840&fm=webp)
[アップデート]AWS Agent Registryが一般提供開始されました!
はじめに
こんにちは、スーパーマーケットが大好きなコンサルティング部の神野です。
2026年8月31日、エージェントやMCPサーバー、スキルをカタログとして管理できる「AWS Agent Registry」がGA(一般提供)になりました!
4月のプレビュー記事では「HTTPSエンドポイントなど他のプロトコルでも登録できると嬉しい」と書いていたのですが、GAでまさにHTTPSエンドポイントのエージェントを登録できるようになりました!これまではA2AのAgent Cardを用意する必要があったので、待望のアップデートです。さらにOrganizations配下のAgentCore RuntimeやGatewayを自動検出する機能も加わり、アカウントごとのエージェント棚卸しの手間も解消されそうな予感ですね。本格的にRegistryらしい機能が備わってきました!
プレビューから何が変わった?
プレビュー版からの差分を、公式ドキュメントやAPIの変更履歴をもとに整理してみました。
| 項目 | プレビュー | GA時点 |
|---|---|---|
| エージェントの記述形式 | A2AのAgent Card | HTTP/AG-UI形式を追加 |
| リソースの登録 | 登録対象の情報やURLを指定 | Organizations配下のRuntime/Gatewayを自動検出する方法を追加 |
| Gatewayの分類 | 専用のレコード種別なし | 自動検出用のGATEWAYを追加 |
| 検出元の情報 | なし | provenanceで元リソースのARN・種別を保持 |
| 利用者向けの取得API | 検索のみ | 承認済みレコードの一覧・詳細の一括取得を追加 |
| RegistryのMCPツール | 検索の1ツール | 検索・一覧・一括取得の3ツール |
| 暗号化 | AWS所有キー | カスタマーマネージドKMSキーを選択可能 |
| SDK・IAMの名前空間 | bedrock-agentcore |
Registry専用のagent-registry |
おお、結構変わりましたね!Org機能の追加やプレビュー時と名前空間が違うのはかなりびっくりしました。なお、承認フローやMCP経由での検索機能などは、プレビュー版の使い勝手を引き継いでいます。
今回は自動検出やHTTPSの登録を試してみたいと思います!
RuntimeとGatewayを自動で登録する
早速1つめとして、Organizations配下のAgentCore RuntimeやGatewayの自動検出を試してみます!
有効化時点の既存リソースだけでなく、後から作成されたリソースも自動で登録されます。接続先が変わればレコードに反映され、元リソースを削除すればレコードも一緒に消えるので、リソースの変化にしっかり追従してくれます。
今回は管理アカウントにRegistryを作成し、自動検出を有効にしました。
AWSは最小権限の観点で委任管理者の利用を推奨していますが、管理アカウント自身で組織スコープのRegistryを作成可能で、必須ではありません。

検出されたレコードにはprovenance(由来)が付与されるので、元のリソースARNからどのアカウントの何のリソースかを追跡できます。
RuntimeはAGENT、GatewayはGATEWAYとして登録されます。
自動承認を無効にしておけば、公開前に管理者のレビューを挟んでガバナンスを効かせる運用も可能です。

自動検出のスコープは現時点で ORGANIZATION のみとなっており、Organizationsと連携せず自アカウント単体でRegistryを運用する場合は、Runtimeも手動で登録が必要です。
とはいえ1アカウントで完結しているなら、AgentCore RuntimeやGatewayの一覧画面を見れば何があるかは把握できますし、数が少ないうちは手で登録していけばなんとかなりそうです。これが10を超えるアカウントに散らばってくると、組織全体で何が動いているかを追うのはさすがに厳しいので、そこが自動検出の出番でしょうかね。
この機能を使うには、信頼されたアクセスとサービスリンクロールの準備が必要です。自動検出の対象は同一リージョン内に限られ、組織・リージョンごとに有効化できるレジストリは1つとなっているので留意しておきましょう。
このあたりの制約は、レジストリの作成画面にもそのまま書かれています。管理アカウントでも委任管理者でもないアカウントで開くと、前提条件を満たしていない旨の警告が出ました。

まずは設定からやってみましょうか!
コンソールでOrganizations連携を設定する
自動検出はコンソールから設定できます。
まず、管理アカウントでAWS Agent Registryを開き、左メニューの「Settings」から「AWS Organizations の設定」の「編集」へ進みます。

「信頼できるアクセスを有効にする」をオンにし、委任管理者の欄は空のまま保存しました。画面の案内では委任管理を「日常的な運用に管理アカウントを使用する代わりに、メンバーアカウントにレジストリ設定の所有権を委任します」と説明していて、欄も「推奨」となっていますが、今回はシンプルに2アカウントで進めます。

有効にすると下記のように表示されました!

同じ管理アカウントで、Registryの作成画面で「自動検出」を有効にします。

今回は公開前にレビューを挟みたいので、自動承認は無効にしています。
既存リソースの初回検出には最大20分かかると公式ドキュメントにあったのでしばらく待ってみたところ、一覧に24件のレコードが表示されました!
狙いどおり、メンバーアカウントのRuntimeとGatewayがしっかりドラフト状態で表示されていますね。

試しにGatewayの1レコードを開くと、「Provenance」に検出元GatewayのARNやリソース種別が入っていて、プロトコルがMCP、認証方式がAWS IAMであることも確認できました!

検出されたドラフトの承認も、この画面から進められます。レコードを選んで「更新ステータス」から「承認用に送信」を選びます。

承認待ちになったレコードは、同じメニューから「承認」「拒否」「非推奨」を選べます。

承認するときは理由も記録できました。承認履歴のコメントとして使えそうです。

こんな感じで承認プロセスを進めていくことができます!厳密には管理者と利用者で権限分離したり、通知を飛ばしたりなど別途作り込み入ると思います。
CLIでも同じ設定を行えます。管理アカウントで設定する手順を以下にまとめます。
CLIでの自動検出の設定・確認・後片付け
以下は公式ドキュメントに沿った手順です。
管理アカウントのAWS CLIプロファイル名を org-management とした例を示します。対象リージョンに既存の自動検出用Registryがないことを確認しておきます。
管理アカウントで信頼されたアクセスを有効にし、サービスリンクロールを作成します。すでに設定済みの操作は省いてください。
aws organizations enable-aws-service-access \
--service-principal agent-registry.amazonaws.com \
--profile org-management
aws iam create-service-linked-role \
--aws-service-name agent-registry.amazonaws.com \
--profile org-management
同じ管理アカウントで、組織を対象とする自動検出を有効にしてRegistryを作成します。
aws agent-registry-control create-registry \
--name registry-ga-autodetection \
--discovery-configuration '{"authorizerType":"AWS_IAM"}' \
--approval-configuration '{"autoApprovalRules":[]}' \
--auto-detection-configuration '{"scope":"ORGANIZATION","enabled":true}' \
--region us-east-1 \
--profile org-management
作成結果のRegistry ARNを環境変数に入れて状態を確認します。
export REGISTRY_ARN='<作成結果のregistryArn>'
aws agent-registry-control get-registry \
--registry-id "$REGISTRY_ARN" \
--query '{registryStatus:status,autoDetection:autoDetection}' \
--region us-east-1 --profile org-management
aws agent-registry-control list-registry-records \
--registry-id "$REGISTRY_ARN" \
--region us-east-1 --profile org-management
Registry本体の状態が READY、自動検出の状態が ACTIVE になっているかを確認します。有効化の設定が true でも、自動検出が実際に稼働しているとは限らないためです。
メンバーアカウントの同じリージョンにRuntimeやGatewayがあれば、そのリソースがレコード一覧に登録される想定です。レコードの詳細取得API(get-registry-record)では、自動検出で作られたことを示す createdByAutoDetection と、元のARNを保持する provenance を確認します。
aws agent-registry-control get-registry-record \
--registry-id "$REGISTRY_ARN" \
--record-id '<一覧に表示されたレコードID>' \
--query '{recordType:recordType,status:status,autoDetected:createdByAutoDetection,provenance:provenance}' \
--region us-east-1 --profile org-management
検証用Registryを削除する際は、先に自動検出を無効にします。
aws agent-registry-control update-registry \
--registry-id "$REGISTRY_ARN" \
--auto-detection-configuration '{"optionalValue":{"scope":"ORGANIZATION","enabled":false}}' \
--region us-east-1 --profile org-management
get-registry でRegistryが READY に戻り、自動検出が INACTIVE になったことを確認したら、一覧の各レコードを削除します。レコードが0件になってからRegistry本体を削除してください。
# 一覧にあるレコードごとに実行
aws agent-registry-control delete-registry-record \
--registry-id "$REGISTRY_ARN" \
--record-id '<削除するレコードID>' \
--region us-east-1 --profile org-management
aws agent-registry-control delete-registry \
--registry-id "$REGISTRY_ARN" \
--region us-east-1 --profile org-management
検証で新しく有効にした信頼されたアクセスも、利用を終える場合は管理アカウントで解除します。既存の組織設定を利用した場合は、その設定を維持してください。
aws organizations disable-aws-service-access \
--service-principal agent-registry.amazonaws.com \
--profile org-management
アカウントが増えるほどありがたい機能ですね!
続いて、GAで追加されたHTTPSエンドポイントの登録も試してみます。
HTTPSエンドポイントを登録してみる
AgentCore RuntimeへデプロイしたエージェントをHTTP形式でレジストリに手動登録して、承認後にレジストリから接続先URLを取得し、計算を依頼するところまで試します。
Organizationsの自動検出とは別の、自アカウント内での検証となります!
| 項目 | 値 |
|---|---|
| 検証日・リージョン | 2026年9月15日・16日・us-east-1 |
| 実行環境 | Python 3.14.6、uv 0.9.26、Node.js 26.7.0 |
| SDK(ローカル) | boto3 / botocore 1.43.89 |
| Runtime | AgentCore CLI 0.27.1(@aws/agentcore)で作成、Python 3.14 |
| モデル | global.anthropic.claude-sonnet-4-5-20250929-v1:0 |
| Registryの設定 | IAM認証・手動承認 |
今回作るエージェントは、AgentCore CLIでサクッと作ってレジストリに登録する形とします。

まずはuvで作業ディレクトリと環境を用意します。
mkdir registry-ga-lab
cd registry-ga-lab
uv init --bare --python 3.14
uv add boto3==1.43.89 botocore==1.43.89
mkdir scripts
計算エージェントを作る
エージェント本体はAgentCore CLIに任せます。npmでインストールします。
npm install -g @aws/agentcore
プロジェクトを作成します。
対話形式のウィザードでも進められますが、今回は手早く済ませたいのでパラメーターを指定して実行します。
プロトコルはHTTP、フレームワークはStrands Agents、モデルプロバイダーはBedrockを選択しています。
agentcore create --project-name registrygalab --name CalculatorAgent \
--framework Strands --model-provider Bedrock --protocol HTTP \
--memory none --build CodeZip --language Python --defaults
作成が完了したらディレクトリを移動して、デプロイします。
cd registrygalab
agentcore deploy
内部でCDKが動いて、Runtime・実行ロール・ロググループがまとめて作られます。
完了するとRuntime ARNが表示されます!
✓ Deployed to 'default' (stack: AgentCore-registrygalab-default)
Outputs:
ApplicationAgentCalculatorAgentRuntimeArnOutput...: arn:aws:bedrock-agentcore:us-east-1:<アカウントID>:runtime/registrygalab_CalculatorAgent-XXXXXXXXXX
ApplicationAgentCalculatorAgentRoleArnOutput...: arn:aws:iam::<アカウントID>:role/AgentCore-registrygalab-d-ApplicationAgentCalculato-XXXXXXXXXXXX
そのままAgentCore CLIから呼び出して動作を確かめます。
agentcore invoke '{"prompt": "What is 2 + 3?"}'
The answer is **5**.
問題なく動いていますね!
表示されたRuntime ARNを環境変数に入れて、Registryへの登録に進みます。
export AGENT_RUNTIME_ARN='<表示されたRuntime ARN>'
Registryの検証コードを用意する
次のコードを scripts/registry_lab.py として保存してください。
これ1本で一連の操作をまかないます。作成したレジストリやレコードのIDは .local/registry-state.json に保存し、後片付けにも使います。
scripts/registry_lab.py(完全版)
"""Disposable AWS Agent Registry GA lab; run with uv run scripts/registry_lab.py."""
import argparse
import json
import os
from pathlib import Path
import time
import uuid
import urllib.request
from urllib.parse import quote
import boto3
from botocore.exceptions import ClientError
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
ROOT = Path(__file__).resolve().parents[1]
STATE_PATH = ROOT / '.local/registry-state.json'
EVENTS_PATH = ROOT / '.local/registry-events.jsonl'
SESSION = boto3.Session(region_name='us-east-1')
CONTROL = SESSION.client('agent-registry-control')
DISCOVERY = SESSION.client('agent-registry')
STATE = json.loads(STATE_PATH.read_text()) if STATE_PATH.exists() else {}
def save():
STATE_PATH.parent.mkdir(mode=0o700, exist_ok=True)
fd = os.open(STATE_PATH, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600)
with os.fdopen(fd, 'w') as stream:
json.dump(STATE, stream, indent=2, default=str)
def event(name, **values):
row = {'event': name, **values}
line = json.dumps(row, ensure_ascii=False, default=str)
print(line, flush=True)
with EVENTS_PATH.open('a') as stream:
stream.write(line + '\n')
def wait_record(record_id, desired='DRAFT'):
for _ in range(150):
result = CONTROL.get_registry_record(registryId=STATE['registryId'], recordId=record_id)
if result['status'] == desired:
return result
if result['status'].endswith('FAILED'):
raise RuntimeError(result.get('statusReason', result['status']))
time.sleep(4)
raise TimeoutError(f'Record did not reach {desired}')
def create_registry():
if 'registryId' not in STATE:
result = CONTROL.create_registry(
name='registry-ga-blog-' + uuid.uuid4().hex[:8],
description='Disposable Agent Registry GA verification',
discoveryConfiguration={'authorizerType': 'AWS_IAM'},
approvalConfiguration={'autoApprovalRules': []},
tags={'Project': 'registry-ga-blog'},
)
STATE.update(registryId=result['registryArn'], records={})
save()
event('registry_created', http_status=result['ResponseMetadata']['HTTPStatusCode'])
for attempt in range(150):
result = CONTROL.get_registry(registryId=STATE['registryId'])
if result['status'] == 'READY':
event('registry_ready', status=result['status'], autoDetection=result.get('autoDetection'))
return
if result['status'].endswith('FAILED'):
raise RuntimeError(result.get('statusReason', result['status']))
if attempt % 8 == 0:
event('registry_wait', status=result['status'])
time.sleep(4)
raise TimeoutError('Registry not ready')
def runtime_url():
arn = os.environ['AGENT_RUNTIME_ARN']
region = arn.split(':')[3]
return f'https://bedrock-agentcore.{region}.amazonaws.com/runtimes/{quote(arn, safe="")}/invocations?qualifier=DEFAULT'
def create_records():
for kind in ('http',):
if kind in STATE['records']:
continue
result = CONTROL.create_registry_record(
registryId=STATE['registryId'], name='calculation-' + kind + '-agent',
displayName='Calculation ' + kind.upper() + ' Agent',
description='Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. '
'POST JSON with a prompt string; returns a text/event-stream response. '
'Authentication: AWS IAM (SigV4). Owner: demo team.',
recordType='AGENT', recordVersion='1.0.0',
descriptors={kind: {'source': {'fromUrl': {'url': runtime_url()}}}},
tags={'Project': 'registry-ga-blog'},
)
record_id = result['recordArn'].rsplit('/', 1)[-1]
STATE['records'][kind] = record_id
save()
event('record_created', kind=kind, status=result['status'])
record = wait_record(record_id)
event('record_ready', kind=kind, status=record['status'], recordType=record['recordType'],
descriptors=record['descriptors'], createdByAutoDetection=record.get('createdByAutoDetection'))
def custom():
definition = {
'endpoint': runtime_url(),
'authentication': {'type': 'AWS_IAM', 'signingService': 'bedrock-agentcore'},
'request': {'method': 'POST', 'contentType': 'application/json',
'example': {'prompt': 'Use add_numbers to calculate 2 + 3.'}},
'response': {'contentType': 'text/event-stream'},
'owner': 'demo team',
}
result = CONTROL.create_registry_record(
registryId=STATE['registryId'], name='calculation-custom-agent',
displayName='Calculation Custom Agent',
description='Adds two numbers. Connection instructions for application developers.',
recordType='AGENT', recordVersion='1.0.0',
descriptors={'custom': {'data': json.dumps(definition)}},
)
rid = result['recordArn'].rsplit('/', 1)[-1]
STATE['records']['custom'] = rid
save()
wait_record(rid)
CONTROL.submit_registry_record_for_approval(registryId=STATE['registryId'], recordId=rid)
wait_record(rid, 'PENDING_APPROVAL')
CONTROL.update_registry_record_status(registryId=STATE['registryId'], recordId=rid,
status='APPROVED', statusReason='Reviewed the example connection instructions.')
wait_record(rid, 'APPROVED')
event('custom_approved', recordType='AGENT', descriptor='custom')
def snapshot(label):
registry_id = STATE['registryId']
managed = CONTROL.list_registry_records(registryId=registry_id)['registryRecords']
discovered = DISCOVERY.list_discoverable_registry_records(registryId=registry_id)['registryRecords']
def summary(records):
return [{key: record.get(key) for key in ('name', 'status', 'recordType', 'description')} for record in records]
event('snapshot', label=label, managed=summary(managed), discovered=summary(discovered))
def approve():
record_id = STATE['records']['http']
current = CONTROL.get_registry_record(registryId=STATE['registryId'], recordId=record_id)
if current['status'] == 'DRAFT':
result = CONTROL.submit_registry_record_for_approval(registryId=STATE['registryId'], recordId=record_id)
event('submitted', status=result['status'])
wait_record(record_id, 'PENDING_APPROVAL')
if current['status'] != 'APPROVED':
result = CONTROL.update_registry_record_status(
registryId=STATE['registryId'], recordId=record_id,
status='APPROVED', statusReason='Reviewed the disposable example metadata.',
)
event('approved', status=result['status'])
wait_record(record_id, 'APPROVED')
def revise():
CONTROL.update_registry_record(
registryId=STATE['registryId'], recordId=STATE['records']['http'],
description={'optionalValue': 'Revised draft: add_numbers accepts two integers.'},
)
result = wait_record(STATE['records']['http'])
event('revised', status=result['status'], description=result['description'])
def batch():
result = DISCOVERY.batch_get_discoverable_registry_record(entries=[{
'registryId': STATE['registryId'], 'recordIds': list(STATE['records'].values()),
}])
event('batch_get', http_status=result['ResponseMetadata']['HTTPStatusCode'],
records=[{'name': r['name'], 'descriptors': r['descriptors']} for r in result['registryRecords']],
errors=[{'kind': next(k for k, v in STATE['records'].items() if v == e['recordId'].rsplit('/', 1)[-1]),
'errorCode': e['errorCode']} for e in result['errors']])
def mcp():
registry_id = STATE['registryId'].rsplit('/', 1)[-1]
url = f'https://agent-registry.us-east-1.api.aws/registry/{registry_id}/mcp'
headers = {'Content-Type': 'application/json', 'Accept': 'application/json, text/event-stream'}
def request(method, params, number):
body = {'jsonrpc': '2.0', 'method': method, 'params': params}
if number is not None:
body['id'] = number
payload = json.dumps(body)
signed = AWSRequest(method='POST', url=url, data=payload, headers=headers)
SigV4Auth(SESSION.get_credentials().get_frozen_credentials(), 'agent-registry', 'us-east-1').add_auth(signed)
req = urllib.request.Request(url, data=payload.encode(), headers=dict(signed.headers.items()), method='POST')
with urllib.request.urlopen(req, timeout=60) as response:
if response.headers.get('Mcp-Session-Id'):
headers['Mcp-Session-Id'] = response.headers['Mcp-Session-Id']
raw = response.read().decode()
if not raw:
return None
if raw.startswith('event:') or raw.startswith('data:'):
raw = next(line[5:].strip() for line in raw.splitlines() if line.startswith('data:'))
result = json.loads(raw)
if 'error' in result:
raise RuntimeError(result['error'])
if number is None:
return result
return result['result']
result = request('initialize', {'protocolVersion': '2025-11-25', 'capabilities': {},
'clientInfo': {'name': 'registry-ga-blog', 'version': '1.0.0'}}, 1)
headers['MCP-Protocol-Version'] = result['protocolVersion']
event('mcp_initialized', protocolVersion=result['protocolVersion'])
request('notifications/initialized', {}, None)
result = request('tools/list', {}, 2)
event('mcp_tools', tools=result['tools'])
result = request('tools/call', {'name': 'list_discoverable_registry_records', 'arguments': {}}, 3)
if result.get('isError'):
raise RuntimeError(result)
event('mcp_list_called', result=result)
result = request('tools/call', {'name': 'search_discoverable_registry_records',
'arguments': {'searchQuery': 'add two numbers calculation', 'maxResults': 5}}, 4)
if result.get('isError'):
raise RuntimeError(result)
event('mcp_search_called', result=result)
result = request('tools/call', {'name': 'batch_get_discoverable_registry_record',
'arguments': {'recordIds': list(STATE['records'].values())}}, 5)
if result.get('isError'):
raise RuntimeError(result)
event('mcp_batch_called', result=result)
def invoke():
result = DISCOVERY.batch_get_discoverable_registry_record(entries=[{
'registryId': STATE['registryId'], 'recordIds': [STATE['records']['http']],
}])
url = result['registryRecords'][0]['descriptors']['http']['source']['fromUrl']['url']
assert url == runtime_url(), 'Unexpected invocation endpoint'
payload = json.dumps({'prompt': 'Use only add_numbers to calculate 2 + 3. Reply with the result.'})
headers = {'Content-Type': 'application/json', 'Accept': 'text/event-stream',
'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id': str(uuid.uuid4())}
signed = AWSRequest(method='POST', url=url, data=payload, headers=headers)
SigV4Auth(SESSION.get_credentials().get_frozen_credentials(), 'bedrock-agentcore', SESSION.region_name).add_auth(signed)
req = urllib.request.Request(url, data=payload.encode(), headers=dict(signed.headers.items()), method='POST')
with urllib.request.urlopen(req, timeout=180) as response:
raw = response.read().decode()
(ROOT / '.local/runtime-response.txt').write_text(raw)
text = ''.join(json.loads(line[6:]).get('event', {}).get('contentBlockDelta', {})
.get('delta', {}).get('text', '')
for line in raw.splitlines() if line.startswith('data: '))
event('runtime_invoked', http_status=response.status,
content_type=response.headers.get('Content-Type'), response_text=text)
def cleanup():
if 'registryId' not in STATE:
return
for kind, record_id in list(STATE['records'].items()):
try:
CONTROL.delete_registry_record(registryId=STATE['registryId'], recordId=record_id)
except ClientError as exc:
if exc.response['Error']['Code'] != 'ResourceNotFoundException':
raise
event('record_deleted', kind=kind)
del STATE['records'][kind]
save()
CONTROL.delete_registry(registryId=STATE['registryId'])
for _ in range(60):
try:
CONTROL.get_registry(registryId=STATE['registryId'])
except ClientError as exc:
if exc.response['Error']['Code'] == 'ResourceNotFoundException':
event('registry_deleted')
STATE.clear()
save()
return
raise
time.sleep(2)
raise TimeoutError('Registry deletion not complete')
if __name__ == '__main__':
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('action', choices=['create', 'snapshot', 'approve', 'revise', 'batch', 'mcp', 'invoke', 'custom', 'cleanup'])
parser.add_argument('--label', default='manual')
args = parser.parse_args()
if args.action == 'create':
create_registry()
create_records()
elif args.action == 'snapshot':
snapshot(args.label)
else:
globals()[args.action]()
初めてRegistryを作成するアカウントでは、サービスリンクロールの作成権限も必要なので注意です。(Adminなどの強い権限であれば気にならないとは思いますが・・・!)
作ったAIエージェントをレジストリに登録してみます!
HTTP形式にURLを指定する
レコードには、接続方法を書いたデータが記述子(descriptor、聴き慣れない日本語ですよね・・・)として入ります。中身は形式ごとに違い、A2AならAgent Card、MCPならサーバーの接続情報、今回のHTTP形式なら接続先のURLです。利用者はカタログでレコードを見つけたあと、この記述子を頼りに接続します。
今回はレコード種別を AGENT にし、記述子に http を指定します。登録部分は次のようになっています。
from urllib.parse import quote
arn = os.environ['AGENT_RUNTIME_ARN']
region = arn.split(':')[3]
url = (
f'https://bedrock-agentcore.{region}.amazonaws.com/'
f'runtimes/{quote(arn, safe="")}/invocations?qualifier=DEFAULT'
)
result = CONTROL.create_registry_record(
registryId=STATE['registryId'],
name='calculation-http-agent',
displayName='Calculation HTTP Agent',
description='Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. '
'POST JSON with a prompt string; returns a text/event-stream response. '
'Authentication: AWS IAM (SigV4). Owner: demo team.',
recordType='AGENT',
recordVersion='1.0.0',
descriptors={'http': {'source': {'fromUrl': {'url': url}}}},
)
AgentCore Runtimeで発行されるURLを指定して登録する形となります!
uv run scripts/registry_lab.py create
{"event": "registry_created", "http_status": 202}
{"event": "registry_wait", "status": "CREATING"}
{"event": "registry_wait", "status": "CREATING"}
{"event": "registry_ready", "status": "READY", "autoDetection": null}
{"event": "record_created", "kind": "http", "status": "CREATING"}
{"event": "record_ready", "kind": "http", "status": "DRAFT", "recordType": "AGENT", "createdByAutoDetection": null}
実行すると、レジストリが READY になり、レコード calculation-http-agent が DRAFT で登録されます!
承認するまで利用者側には未承認のレコードは見えない
利用者向けのAPIにはagent-registryクライアントを使います。管理用のagent-registry-controlとはクライアントが分かれている点がポイントです。登録したレコードがいつ利用者から見えるようになるのか、承認の前後で1ステップずつ確かめていきます。
管理用の一覧と利用者向けの一覧を1回ずつ呼び出して記録します。
managed = CONTROL.list_registry_records(registryId=registry_id)['registryRecords']
discovered = DISCOVERY.list_discoverable_registry_records(registryId=registry_id)['registryRecords']
まず、承認前の状態を取得してきます。
uv run scripts/registry_lab.py snapshot --label before-approval
実行結果(承認前)
{
"event": "snapshot",
"label": "before-approval",
"managed": [
{
"name": "calculation-http-agent",
"status": "DRAFT",
"recordType": "AGENT",
"description": "Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. POST JSON with a prompt string; returns a text/event-stream response. Authentication: AWS IAM (SigV4). Owner: demo team."
}
],
"discovered": []
}
管理用の一覧(managed)にはDRAFTで1件入っていますが、利用者向けの一覧(discovered)は空です。利用者向けの検索API(search_discoverable_registry_records)も同じで、承認前に実行したときは0件でした。一覧も検索も、ヒットするのは承認済みのレコードだけです。
次に承認を実施します。
作成者が承認依頼を行い、ステータスをPENDING_APPROVAL(承認待ち)にしてから、管理者がステータスをAPPROVED(承認)へ更新する、2段階で進めるイメージです。
CONTROL.submit_registry_record_for_approval(registryId=STATE['registryId'], recordId=record_id)
wait_record(record_id, 'PENDING_APPROVAL')
CONTROL.update_registry_record_status(
registryId=STATE['registryId'], recordId=record_id,
status='APPROVED', statusReason='Reviewed the disposable example metadata.',
)
uv run scripts/registry_lab.py approve
{"event": "submitted", "status": "PENDING_APPROVAL"}
{"event": "approved", "status": "APPROVED"}
承認したので、もう一度一覧を取ってみて状態を確認してみましょうか。
uv run scripts/registry_lab.py snapshot --label after-approval
実行結果(承認後)
{
"event": "snapshot",
"label": "after-approval",
"managed": [
{
"name": "calculation-http-agent",
"status": "APPROVED",
"recordType": "AGENT",
"description": "Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. POST JSON with a prompt string; returns a text/event-stream response. Authentication: AWS IAM (SigV4). Owner: demo team."
}
],
"discovered": [
{
"name": "calculation-http-agent",
"status": "APPROVED",
"recordType": "AGENT",
"description": "Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. POST JSON with a prompt string; returns a text/event-stream response. Authentication: AWS IAM (SigV4). Owner: demo team."
}
]
}
利用者向けの一覧にも、APPROVEDで1件現れましたね!
この状態で、承認済みレコードの説明文を書き換えた場合の挙動も確認してみます。
update_registry_recordで、optionalValueに新しい説明文を指定して更新します。
CONTROL.update_registry_record(
registryId=STATE['registryId'], recordId=STATE['records']['http'],
description={'optionalValue': 'Revised draft: add_numbers accepts two integers.'},
)
uv run scripts/registry_lab.py revise
{"event": "revised", "status": "DRAFT", "description": "Revised draft: add_numbers accepts two integers."}
更新した時点で、管理側のステータスはAPPROVEDからDRAFTに戻りました。この状態で管理側と利用者側の見え方を比べてみます。
uv run scripts/registry_lab.py snapshot --label after-revision
実行結果(説明文の更新後)
{
"event": "snapshot",
"label": "after-revision",
"managed": [
{
"name": "calculation-http-agent",
"status": "DRAFT",
"recordType": "AGENT",
"description": "Revised draft: add_numbers accepts two integers."
}
],
"discovered": [
{
"name": "calculation-http-agent",
"status": "APPROVED",
"recordType": "AGENT",
"description": "Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. POST JSON with a prompt string; returns a text/event-stream response. Authentication: AWS IAM (SigV4). Owner: demo team."
}
]
}
| 見え方 | 管理用の一覧 | 利用者向けの一覧・検索 |
|---|---|---|
| ステータス | DRAFT |
APPROVED |
| 説明文 | 更新後の新しい説明 | 承認済みの古い説明 |
管理側では更新後の内容が反映されて再レビュー待ちになる一方、利用者側には承認済みの古い説明がそのまま公開され続けます。
再レビュー中でも公開中の情報は消えず、カタログとしては常に承認済みのレコードが表示される仕組みで安心ですね!
MCPにも対応している
レジストリはAPIだけでなく、MCPにも対応しています。プレビュー時よりも対応しているツールが増えていますね!
| ツール | 返却される情報 |
|---|---|
list_discoverable_registry_records |
ID、名前、表示名、説明、種別、バージョン、承認状態、記述子の種類。URLなどの記述子本文は含まれない |
search_discoverable_registry_records |
検索に一致したレコード。今回は説明とHTTP記述子のURLも含まれる |
batch_get_discoverable_registry_record |
指定したIDの詳細。HTTP記述子のURLを取得できた |
3つとも利用者向けのツールなので、SDKのときと同じく、返ってくるのは承認済みのレコードだけです。
MCPのスクリプトも用意しているので、実行してみます。
uv run scripts/registry_lab.py mcp
それぞれのリクエストと応答は次のとおりです。応答は content[].text に入っているJSON文字列を整形し、IDは置換しています。
list_discoverable_registry_records
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "list_discoverable_registry_records",
"arguments": {}
}
}
{
"registryRecords": [
{
"recordArn": "arn:aws:agent-registry:us-east-1:<ACCOUNT_ID>:registry/<REGISTRY_ID>/record/<RECORD_ID>",
"recordId": "<RECORD_ID>",
"name": "calculation-http-agent",
"displayName": "Calculation HTTP Agent",
"description": "Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. POST JSON with a prompt string; returns a text/event-stream response. Authentication: AWS IAM (SigV4). Owner: demo team.",
"recordType": "AGENT",
"recordVersion": "1.0.0",
"status": "APPROVED",
"createdAt": "2026-09-15T04:48:58.608183099Z",
"updatedAt": "2026-09-15T04:49:56.904363846Z",
"descriptorTypes": [
"http"
]
}
]
}
descriptorTypes で記述子の種類は分かりますが、URLなどの本文は含まれません。
search_discoverable_registry_records
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "search_discoverable_registry_records",
"arguments": {
"searchQuery": "add two numbers calculation",
"maxResults": 5
}
}
}
[
{
"recordId": "<RECORD_ID>",
"name": "calculation-http-agent",
"displayName": "Calculation HTTP Agent",
"description": "Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. POST JSON with a prompt string; returns a text/event-stream response. Authentication: AWS IAM (SigV4). Owner: demo team.",
"recordType": "AGENT",
"descriptors": {
"mcpServer": null,
"a2aAgentCard": null,
"agentSkillsDefinition": null,
"custom": null,
"http": {
"source": {
"fromUrl": {
"url": "https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/arn%3Aaws%3Abedrock-agentcore%3Aus-east-1%3A<ACCOUNT_ID>%3Aruntime%2F<RUNTIME_ID>/invocations?qualifier=DEFAULT"
}
}
},
"agui": null
},
"recordVersion": "1.0.0",
"status": "APPROVED"
}
]
一覧と違い、記述子の本文まで返ります。未使用の記述子は null で並びます。
batch_get_discoverable_registry_record
{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "batch_get_discoverable_registry_record",
"arguments": {
"recordIds": ["<RECORD_ID>"]
}
}
}
{
"registryRecords": [
{
"registryArn": "arn:aws:agent-registry:us-east-1:<ACCOUNT_ID>:registry/<REGISTRY_ID>",
"recordArn": "arn:aws:agent-registry:us-east-1:<ACCOUNT_ID>:registry/<REGISTRY_ID>/record/<RECORD_ID>",
"recordId": "<RECORD_ID>",
"name": "calculation-http-agent",
"description": "Adds two numbers using the add_numbers tool. Hosted on AgentCore Runtime. POST JSON with a prompt string; returns a text/event-stream response. Authentication: AWS IAM (SigV4). Owner: demo team.",
"displayName": "Calculation HTTP Agent",
"recordType": "AGENT",
"descriptors": {
"mcpServer": null,
"a2aAgentCard": null,
"agentSkillsDefinition": null,
"custom": null,
"http": {
"source": {
"fromUrl": {
"url": "https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/arn%3Aaws%3Abedrock-agentcore%3Aus-east-1%3A<ACCOUNT_ID>%3Aruntime%2F<RUNTIME_ID>/invocations?qualifier=DEFAULT"
}
}
},
"agui": null
},
"recordVersion": "1.0.0",
"status": "APPROVED",
"createdAt": "2026-09-15T04:48:58.608183099Z",
"updatedAt": "2026-09-15T04:49:05.596253649Z"
}
],
"errors": []
}
指定したIDのレコードが registryRecords に入り、記述子の本文まで返ります。
HTTP記述子から分かるのは接続先URLなどです。今回の用途・入力形式・認証方式・管理担当は、登録時に説明文へ記載しました。こうした情報があると、利用者が候補を選び、呼び出し方を確認しやすくなります。
利用者Agent側の使い方としては、次の図のように、一覧や検索で候補を絞り込み、選んだレコードだけ一括取得で記述子まで取り出す、という2段構えになります。一覧はURLなどの本文を返さないぶん応答が軽いので、候補選びと接続情報の取得を使い分けられます。

取得したURLへアプリから接続する
通常のアプリでもSDKからカタログを検索・取得できるので、今回は一括取得したHTTP記述子のURLへ、PythonからIAM認証(SigV4署名)付きでPOSTしてみます。
result = DISCOVERY.batch_get_discoverable_registry_record(entries=[{
'registryId': STATE['registryId'], 'recordIds': [STATE['records']['http']],
}])
url = result['registryRecords'][0]['descriptors']['http']['source']['fromUrl']['url']
payload = json.dumps({'prompt': 'Use only add_numbers to calculate 2 + 3. Reply with the result.'})
headers = {'Content-Type': 'application/json', 'Accept': 'text/event-stream',
'X-Amzn-Bedrock-AgentCore-Runtime-Session-Id': str(uuid.uuid4())}
signed = AWSRequest(method='POST', url=url, data=payload, headers=headers)
SigV4Auth(SESSION.get_credentials().get_frozen_credentials(), 'bedrock-agentcore', SESSION.region_name).add_auth(signed)
uv run scripts/registry_lab.py invoke
{
"http_status": 200,
"content_type": "text/event-stream; charset=utf-8",
"response_text": "The result is **5**."
}
Registryから接続先を取得し、Runtime上の add_numbers を使った計算結果が返りました!エージェントが動的に候補を探す用途に加え、業務アプリから既存のエージェントを呼び出すときにも使えそうですね!
コンソールの登録画面も確認する
ここまではSDKで登録してきましたが、コンソールの登録画面も見ておきます。Registryの詳細から「レコードを作成」を開き、「ソース」と「手動で定義」の両方でエージェントを選択してみましたが、HTTP形式の選択肢は表示されませんでした。手動定義では、次の3種類が表示されています。

HTTP形式そのものは選べませんが、タイプ「エージェント」+記述子「カスタム」なら、接続先URLや認証方式を独自のJSONとして登録できます。
ただし、これは今回SDKで登録したHTTP記述子とは別形式のレコードです。ややこしいですね・・・
違いを整理すると次のようになります。
| 観点 | HTTP記述子 | カスタム記述子 |
|---|---|---|
| 登録方法 | SDK・CLI(コンソールに選択肢なし) | コンソール・SDKの両方 |
| 記述子の中身 | 接続先URLのみ(構造は固定) | 自由なJSON文字列 |
| 取得時の返り方 | http.source.fromUrl.url にURLが入る |
custom.data に文字列のまま入る |
| 利用側の実装 | URLをそのまま接続先に使える | JSONを解釈して接続情報を取り出す |
Registryはカスタム記述子の中身を解釈しないので、項目の決め方と読み方は利用側とそろえておく必要があります。そこを許容できるなら、コンソールから登録する場合の選択肢になります。
AgentCore Runtimeをカスタム記述子で載せるなら、たとえば次のようなJSONになります。項目名はスキーマのない自由定義で、今回の検証用に決めたものです。この内容をSDK(descriptors={'custom': {'data': ...}})で登録し、承認からMCPでの取得まで可能です。
カスタム記述子のJSON例(AgentCore Runtime)
{
"endpoint": "https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/<URLエンコードしたRuntime ARN>/invocations?qualifier=DEFAULT",
"authentication": {
"type": "AWS_IAM",
"signingService": "bedrock-agentcore"
},
"request": {
"method": "POST",
"contentType": "application/json",
"example": {"prompt": "Use add_numbers to calculate 2 + 3."}
},
"response": {"contentType": "text/event-stream"},
"owner": "demo team"
}
呼び出し先URLや署名サービス名、入出力の形式をまとめて定義しておけば、利用側はこのJSONをパースして接続処理を組み立てられます。
SDKやCLIだけでなく・・・コンソールでも同じようにRuntimeを簡単に登録できるようになると・・・嬉しいですね・・・!(もし私の見落としで、コンソールからも登録できるようなら教えてください・・・!)
それか自アカウント内だけ検出できるようになるとかでも・・・!
暗号化とイベント通知
セキュリティ面では、カスタマーマネージドKMSキーに対応しました。descriptorや検索インデックスを自前のKMSキーで暗号化できます。このキーはレジストリ作成時に指定します。作成後の変更はできません。名前や説明といったメタデータについては、従来どおりAWS所有キーで暗号化されます。
また、EventBridgeの通知イベントも拡充されました。承認・拒否・非推奨化(Deprecated)などのステータス変更を通知できます。
プレビューから使っている人は移行が必要
プレビュー版から触っていた方は注意が必要で、旧 bedrock-agentcore 名前空間の Registry は 2026年9月17日に読み書きができなくなる予定です。データの自動移行は行われないため、新しいレジストリへ手動で移す必要があります。
前回の記事で書いたコードからも、主に以下の指定が変わっています。
| 変更箇所 | 旧 | 新 |
|---|---|---|
| 管理用クライアント | bedrock-agentcore-control |
agent-registry-control |
| 利用者向けクライアント | bedrock-agentcore |
agent-registry |
| 検索メソッド | search_registry_records() |
search_discoverable_registry_records() |
| Registry用IAMアクション | bedrock-agentcore: |
agent-registry: |
| descriptorの本文 | inlineContent |
data |
descriptorの構造やRegistry本体のARN、MCPの接続先も変わっています。移行時は、クライアント名と合わせて確認してください。
エージェントの動的な利用にもつなげる
A2A形式のRuntimeもOrganizationsの自動検出対象です。
登録内容を確認・補足して承認すれば、以前試した、Registryで接続先を探してStrands AgentsからA2Aで呼び出す構成にもつなげられそうです!勝手にA2Aで幅広く色々なエージェントと繋がっていく未来は面白そうですね・・・!
精度とのトレードオフになりますし、頻繁に繋がりまくってもレイテンシーとか気になるので悩ましいポイントも多くありそうですが・・・!
動的な利用はA2Aに限らず、HTTP形式のレコードでも同じように扱えます!
今回のサンプルのようにカタログからURLを取得して呼び出す処理をアプリに入れておけば、社内のカタログアプリからエージェントを探してそのまま試す、といった使い方ができそうですね。
また、エージェント側が実行時にRegistryを検索して、見つけた相手をHTTPSのAPIとしてツールで呼び出したい場面でも使えそうです!
組織でどう使うか
今回試したようにOrganizations連携で自動検出を有効にすると、組織内の同一リージョンのRuntime・Gatewayが登録され、それ以外の環境で動くエージェントも、HTTPSエンドポイントを手動登録して同じカタログに載せられます。

たとえば、営業アプリからサポートチームの注文確認エージェントを呼び出したいケースを考えてみます。
開発者がRegistryで承認済みの候補を検索し、接続先と入出力仕様を確認して、営業アプリに呼び出し処理を実装します。実行時は、そのエージェントが求める認証・権限で接続します。既存の注文確認処理を使えるので、別チームで作り直す手間を減らせそうです!またコミュニケーションのきっかけになって、カタログに載っているエージェントの作り方とかも聞いたりなどもしやすくなるのかなーとか思いました。
AWS Organizationsを使っているなら、エージェント管理用のメンバーアカウントを委任管理者にして、Registryで情報を集約・承認する構成が良さそうに思えますね!管理用アカウントのRegistryをAWS RAMで各チームのアカウントへ共有すれば、各チームが共通のカタログからエージェントを探せます!以下はRAM共有を使う構成のイメージです。

クロスアカウント共有の詳しい仕様は公式ドキュメントもあわせて確認してみてください。
今回は試していないので、また別の記事で検証したいですね!
後片付け
最後に、今回作成したレコードとレジストリを削除しておきます。
uv run scripts/registry_lab.py cleanup
{"event": "record_deleted", "kind": "http"}
{"event": "registry_deleted"}
レコードが残っているとレジストリを削除できないため、先にレコードをすべて削除してからレジストリ本体を削除します。
for kind, record_id in list(STATE['records'].items()):
CONTROL.delete_registry_record(registryId=STATE['registryId'], recordId=record_id)
CONTROL.delete_registry(registryId=STATE['registryId'])
Runtime側はAgentCore CLIで片付けます。agentcore remove all はプロジェクトの定義を空にするコマンドなので、そのあとに agentcore deploy を実行して、空の状態をAWSへ反映させます。
cd registrygalab
agentcore remove all -y
agentcore deploy
CloudFormationスタックごと消えるので、Runtimeと一緒に実行ロールやロググループも削除されます。
おわりに
前回のプレビュー記事で気になっていたHTTPS URLの登録を試せて、Organizationsの自動検出も確認できました!
AWS RAMによるアカウント間共有のほか、カスタマーマネージドKMSキーによる暗号化、EventBridgeと連携した承認通知など、まだ試したい機能がいろいろありますし、Registryの運用も腰を据えて考えてみたいですね!今回はエージェントのカタログにフォーカスしていますが、スキルやMCPも管理できますからね。実際の運用イメージなどこれからブログもどしどし書いていければと思います!!(エンプラの希望の星になって欲しいです)
本記事が少しでも参考になりましたら幸いです。最後までご覧いただきありがとうございました!








