Generate A2A Agent Card
Generate an A2A (Agent-to-Agent) protocol agent card JSON file by analyzing the source code at $ARGUMENTS.
Steps
1. Carefully study the source code
Do NOT just skim the top-level files. Agents can be complex, multi-file projects. You MUST thoroughly explore the entire folder structure before generating the card.
If $ARGUMENTS is a local folder path, use Glob to find ALL Python files, YAML/JSON configs, and README files in the folder and its subfolders. Read every relevant file.
If $ARGUMENTS is a GitHub URL, use WebFetch to read the raw file contents. Follow imports to discover additional files.
Where to look (agents are not always a single file):
- Entrypoints:
main.py, app.py, agent_entrypoint.py, server.py, __main__.py
- Tool definitions: tools may be in separate files like
tools/, skills/, functions/, or registered via decorators (@tool, @function_tool, @mcp_tool)
- Multi-agent setups: look for orchestrator/supervisor patterns, multiple agent classes, agent registries, sub-agent folders
- Prompts and system messages: may be in separate files like
prompts/, templates/, system_prompt.txt, or as string constants
- MCP server connections: look for MCP client configs,
mcp_servers, MCPClient, tool imports from MCP servers - these are skills the agent can use
- Config files:
pyproject.toml, requirements.txt, .bedrock_agentcore.yaml, agent_config.yaml, docker-compose.yml
- Sub-folders: check ALL subdirectories for additional agents, tools, or shared utilities
From the code, detect:
- Agent name: from constants, CLI args, config files, class names
- Description: from docstrings, README, module-level comments
- Skills/tools: from
@tool decorators, tool lists, function definitions passed to agent frameworks (Strands, LangChain, CrewAI, AutoGen, etc.), MCP tool connections, imported tool modules
- Multi-agent skills: if there are multiple agents (orchestrator, sub-agents), each agent's capabilities should be represented as skills
- MCP-sourced tools: if the agent connects to MCP servers, list those tools as skills too (read the MCP server configs to find tool names and descriptions)
- Input/output modes: text, images, files, structured data - check what the agent accepts and returns
- Protocol: HTTP (
HTTP+JSON), A2A (JSONRPC), MCP
- Auth mechanism: IAM/SigV4, Cognito/JWT, API key, OAuth2
- Streaming support: from framework config, capabilities flags
- Version: from constants, pyproject.toml, or default to
1.0.0
- Endpoint URL: from
.bedrock_agentcore.yaml or deployment config if available
2. Generate the agent card JSON
Create a JSON file following the official A2A Agent Card specification (https://a2a-protocol.org/latest/specification/).
All mandatory fields MUST be present. Use camelCase for JSON field names.
Required fields
{
"name": "string - Human-readable agent name",
"description": "string - What the agent does",
"version": "string - e.g. 1.0.0",
"supportedInterfaces": [
{
"url": "string - Agent endpoint URL",
"protocolBinding": "string - JSONRPC or HTTP+JSON or GRPC",
"protocolVersion": "string - e.g. 1.0"
}
],
"capabilities": {
"streaming": false,
"pushNotifications": false
},
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "string - unique skill id",
"name": "string - human-readable name",
"description": "string - what the skill does",
"tags": ["string"],
"examples": ["string - example prompts"]
}
]
}
Optional fields to include when detected
provider: Include if organization info is available. Requires organization (string) and url (string).
documentationUrl: Link to docs if found in README or code.
iconUrl: Agent icon if found.
securitySchemes: Include when auth is detected:
- Cognito/JWT:
{"bearerAuth": {"httpAuthSecurityScheme": {"scheme": "Bearer", "description": "Cognito JWT bearer token"}}}
- API Key:
{"apiKey": {"apiKeySecurityScheme": {"name": "x-api-key", "location": "header"}}}
- IAM/SigV4:
{"sigv4": {"httpAuthSecurityScheme": {"scheme": "AWS4-HMAC-SHA256", "description": "AWS SigV4 request signing"}}}
securityRequirements: Reference the schemes defined above, e.g. [{"schemes": {"bearerAuth": []}}]
3. Populate skills correctly
- Find ALL tools/functions the agent exposes
- For each tool, create a skill entry with:
id: snake_case identifier
name: Human-readable name
description: From the function docstring or tool description
tags: Relevant categories (e.g. ["math", "calculator"], ["search", "web"])
examples: 2-3 example prompts showing usage
4. Set the endpoint URL
- Check for
.bedrock_agentcore.yaml in the agent folder and read the ARN/endpoint if available
- If no config found, use placeholder:
https://<AGENT_ENDPOINT_URL>/
5. Detect protocol binding
- A2A agents (a2a_server, A2AServer, port 9000, protocol="A2A"): use
JSONRPC
- HTTP agents (BedrockAgentCoreApp, REST endpoints): use
HTTP+JSON
- Default to
JSONRPC
6. Save the output
- Name the file
{agent_name}_agent_card.json using the detected agent name in snake_case
- Save it in the agent's folder (same folder as the source code)
- Pretty-print with 2-space indentation
7. Validate the generated JSON
After writing the file, validate it by running this Python script via Bash:
python3 -c "
import json
import sys
file_path = '<OUTPUT_FILE_PATH>'
# Step 1: JSON format check
try:
with open(file_path) as f:
card = json.load(f)
print('PASS: Valid JSON format')
except json.JSONDecodeError as e:
print(f'FAIL: Invalid JSON - {e}')
sys.exit(1)
# Step 2: Required top-level fields
errors = []
TOP_LEVEL_REQUIRED = ['name', 'description', 'version', 'supportedInterfaces', 'capabilities', 'defaultInputModes', 'defaultOutputModes', 'skills']
for field in TOP_LEVEL_REQUIRED:
if field not in card:
errors.append(f'Missing required top-level field: {field}')
elif field in ('name', 'description', 'version') and not isinstance(card[field], str):
errors.append(f'{field} must be a string')
elif field in ('defaultInputModes', 'defaultOutputModes', 'skills', 'supportedInterfaces') and not isinstance(card[field], list):
errors.append(f'{field} must be an array')
elif field == 'capabilities' and not isinstance(card[field], dict):
errors.append(f'{field} must be an object')
# Step 3: Validate supportedInterfaces entries
INTERFACE_REQUIRED = ['url', 'protocolBinding', 'protocolVersion']
for i, iface in enumerate(card.get('supportedInterfaces', [])):
for field in INTERFACE_REQUIRED:
if field not in iface:
errors.append(f'supportedInterfaces[{i}] missing required field: {field}')
binding = iface.get('protocolBinding', '')
if binding and binding not in ('JSONRPC', 'GRPC', 'HTTP+JSON'):
errors.append(f'supportedInterfaces[{i}].protocolBinding must be JSONRPC, GRPC, or HTTP+JSON, got: {binding}')
if not card.get('supportedInterfaces'):
errors.append('supportedInterfaces must have at least one entry')
# Step 4: Validate skills entries
SKILL_REQUIRED = ['id', 'name', 'description', 'tags']
for i, skill in enumerate(card.get('skills', [])):
for field in SKILL_REQUIRED:
if field not in skill:
errors.append(f'skills[{i}] missing required field: {field}')
if 'tags' in skill and not isinstance(skill['tags'], list):
errors.append(f'skills[{i}].tags must be an array')
# Step 5: Validate defaultInputModes/defaultOutputModes are non-empty
if not card.get('defaultInputModes'):
errors.append('defaultInputModes must have at least one entry')
if not card.get('defaultOutputModes'):
errors.append('defaultOutputModes must have at least one entry')
# Step 6: Validate provider if present
if 'provider' in card and card['provider'] is not None:
for field in ('organization', 'url'):
if field not in card['provider']:
errors.append(f'provider missing required field: {field}')
# Step 7: Report results
if errors:
print(f'FAIL: {len(errors)} validation error(s):')
for e in errors:
print(f' - {e}')
sys.exit(1)
else:
skill_count = len(card.get('skills', []))
iface_count = len(card.get('supportedInterfaces', []))
print(f'PASS: All mandatory fields present ({iface_count} interface(s), {skill_count} skill(s))')
"
Replace <OUTPUT_FILE_PATH> with the actual path of the generated JSON file.
If validation fails, fix the errors in the JSON and re-run validation until all checks pass. Do NOT report success to the user until validation passes.
8. Report results
After validation passes, output results in EXACTLY this format:
Validation passed. Here's a summary of the generated agent card:
Output file: <filename>.json
Detected from code:
- Agent name: <AgentName> (from <how it was detected, e.g. Strands agent with BedrockAgentCoreApp>)
- Skills: <count> - <skill_id> (<brief description>), <skill_id> (<brief description>), ...
- Protocol: <HTTP+JSON or JSONRPC> (<why, e.g. uses BedrockAgentCoreApp on port 8080>)
- Auth: <auth mechanisms detected, e.g. IAM/SigV4 (default) + Cognito JWT (optional)>
- Streaming: <true or false>
- Endpoint URL: <source, e.g. From .bedrock_agentcore.yaml - uses the my_agent deployment ARN (account ..., region ...)> or <Placeholder used - no deployment config found>
If validation fails, show the errors first, fix them, re-validate, and only show the summary above after all checks pass.
Reference template
Use this as a structural reference (from simple-a2a-agent):
{
"name": "SimpleCalculatorAgent",
"description": "A simple calculator agent that can evaluate mathematical expressions.",
"version": "1.0.0",
"supportedInterfaces": [
{
"url": "https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/<encoded-arn>/invocations/",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": {
"streaming": true,
"pushNotifications": false
},
"defaultInputModes": ["text/plain"],
"defaultOutputModes": ["text/plain"],
"skills": [
{
"id": "calculator",
"name": "Calculator",
"description": "Evaluate a mathematical expression and return the result.",
"tags": ["math", "calculator", "arithmetic"],
"examples": [
"What is 42 * 17?",
"Calculate the square root of 144",
"What is 15% of 200?"
]
}
]
}
1---2name: generate-agent-card3description: Generate an A2A agent card JSON by analyzing agent source code in a folder or GitHub URL. Studies the code to detect agent name, skills, tools, auth, protocol, and generates a spec-compliant agent card.4---56# Generate A2A Agent Card78Generate an A2A (Agent-to-Agent) protocol agent card JSON file by analyzing the source code at `$ARGUMENTS`.910## Steps1112### 1. Carefully study the source code1314Do NOT just skim the top-level files. Agents can be complex, multi-file projects. You MUST thoroughly explore the entire folder structure before generating the card.1516If `$ARGUMENTS` is a local folder path, use Glob to find ALL Python files, YAML/JSON configs, and README files in the folder and its subfolders. Read every relevant file.1718If `$ARGUMENTS` is a GitHub URL, use `WebFetch` to read the raw file contents. Follow imports to discover additional files.1920**Where to look** (agents are not always a single file):2122- **Entrypoints**: `main.py`, `app.py`, `agent_entrypoint.py`, `server.py`, `__main__.py`23- **Tool definitions**: tools may be in separate files like `tools/`, `skills/`, `functions/`, or registered via decorators (`@tool`, `@function_tool`, `@mcp_tool`)24- **Multi-agent setups**: look for orchestrator/supervisor patterns, multiple agent classes, agent registries, sub-agent folders25- **Prompts and system messages**: may be in separate files like `prompts/`, `templates/`, `system_prompt.txt`, or as string constants26- **MCP server connections**: look for MCP client configs, `mcp_servers`, `MCPClient`, tool imports from MCP servers - these are skills the agent can use27- **Config files**: `pyproject.toml`, `requirements.txt`, `.bedrock_agentcore.yaml`, `agent_config.yaml`, `docker-compose.yml`28- **Sub-folders**: check ALL subdirectories for additional agents, tools, or shared utilities2930From the code, detect:3132- **Agent name**: from constants, CLI args, config files, class names33- **Description**: from docstrings, README, module-level comments34- **Skills/tools**: from `@tool` decorators, tool lists, function definitions passed to agent frameworks (Strands, LangChain, CrewAI, AutoGen, etc.), MCP tool connections, imported tool modules35- **Multi-agent skills**: if there are multiple agents (orchestrator, sub-agents), each agent's capabilities should be represented as skills36- **MCP-sourced tools**: if the agent connects to MCP servers, list those tools as skills too (read the MCP server configs to find tool names and descriptions)37- **Input/output modes**: text, images, files, structured data - check what the agent accepts and returns38- **Protocol**: HTTP (`HTTP+JSON`), A2A (`JSONRPC`), MCP39- **Auth mechanism**: IAM/SigV4, Cognito/JWT, API key, OAuth240- **Streaming support**: from framework config, capabilities flags41- **Version**: from constants, pyproject.toml, or default to `1.0.0`42- **Endpoint URL**: from `.bedrock_agentcore.yaml` or deployment config if available4344### 2. Generate the agent card JSON4546Create a JSON file following the official A2A Agent Card specification (https://a2a-protocol.org/latest/specification/).4748All mandatory fields MUST be present. Use camelCase for JSON field names.4950#### Required fields5152```json53{54 "name": "string - Human-readable agent name",55 "description": "string - What the agent does",56 "version": "string - e.g. 1.0.0",57 "supportedInterfaces": [58 {59 "url": "string - Agent endpoint URL",60 "protocolBinding": "string - JSONRPC or HTTP+JSON or GRPC",61 "protocolVersion": "string - e.g. 1.0"62 }63 ],64 "capabilities": {65 "streaming": false,66 "pushNotifications": false67 },68 "defaultInputModes": ["text/plain"],69 "defaultOutputModes": ["text/plain"],70 "skills": [71 {72 "id": "string - unique skill id",73 "name": "string - human-readable name",74 "description": "string - what the skill does",75 "tags": ["string"],76 "examples": ["string - example prompts"]77 }78 ]79}80```8182#### Optional fields to include when detected8384- `provider`: Include if organization info is available. Requires `organization` (string) and `url` (string).85- `documentationUrl`: Link to docs if found in README or code.86- `iconUrl`: Agent icon if found.87- `securitySchemes`: Include when auth is detected:88 - Cognito/JWT: `{"bearerAuth": {"httpAuthSecurityScheme": {"scheme": "Bearer", "description": "Cognito JWT bearer token"}}}`89 - API Key: `{"apiKey": {"apiKeySecurityScheme": {"name": "x-api-key", "location": "header"}}}`90 - IAM/SigV4: `{"sigv4": {"httpAuthSecurityScheme": {"scheme": "AWS4-HMAC-SHA256", "description": "AWS SigV4 request signing"}}}`91- `securityRequirements`: Reference the schemes defined above, e.g. `[{"schemes": {"bearerAuth": []}}]`9293### 3. Populate skills correctly9495- Find ALL tools/functions the agent exposes96- For each tool, create a skill entry with:97 - `id`: snake_case identifier98 - `name`: Human-readable name99 - `description`: From the function docstring or tool description100 - `tags`: Relevant categories (e.g. `["math", "calculator"]`, `["search", "web"]`)101 - `examples`: 2-3 example prompts showing usage102103### 4. Set the endpoint URL104105- Check for `.bedrock_agentcore.yaml` in the agent folder and read the ARN/endpoint if available106- If no config found, use placeholder: `https://<AGENT_ENDPOINT_URL>/`107108### 5. Detect protocol binding109110- A2A agents (a2a_server, A2AServer, port 9000, protocol="A2A"): use `JSONRPC`111- HTTP agents (BedrockAgentCoreApp, REST endpoints): use `HTTP+JSON`112- Default to `JSONRPC`113114### 6. Save the output115116- Name the file `{agent_name}_agent_card.json` using the detected agent name in snake_case117- Save it in the agent's folder (same folder as the source code)118- Pretty-print with 2-space indentation119120### 7. Validate the generated JSON121122After writing the file, validate it by running this Python script via Bash:123124```bash125python3 -c "126import json127import sys128129file_path = '<OUTPUT_FILE_PATH>'130131# Step 1: JSON format check132try:133 with open(file_path) as f:134 card = json.load(f)135 print('PASS: Valid JSON format')136except json.JSONDecodeError as e:137 print(f'FAIL: Invalid JSON - {e}')138 sys.exit(1)139140# Step 2: Required top-level fields141errors = []142TOP_LEVEL_REQUIRED = ['name', 'description', 'version', 'supportedInterfaces', 'capabilities', 'defaultInputModes', 'defaultOutputModes', 'skills']143for field in TOP_LEVEL_REQUIRED:144 if field not in card:145 errors.append(f'Missing required top-level field: {field}')146 elif field in ('name', 'description', 'version') and not isinstance(card[field], str):147 errors.append(f'{field} must be a string')148 elif field in ('defaultInputModes', 'defaultOutputModes', 'skills', 'supportedInterfaces') and not isinstance(card[field], list):149 errors.append(f'{field} must be an array')150 elif field == 'capabilities' and not isinstance(card[field], dict):151 errors.append(f'{field} must be an object')152153# Step 3: Validate supportedInterfaces entries154INTERFACE_REQUIRED = ['url', 'protocolBinding', 'protocolVersion']155for i, iface in enumerate(card.get('supportedInterfaces', [])):156 for field in INTERFACE_REQUIRED:157 if field not in iface:158 errors.append(f'supportedInterfaces[{i}] missing required field: {field}')159 binding = iface.get('protocolBinding', '')160 if binding and binding not in ('JSONRPC', 'GRPC', 'HTTP+JSON'):161 errors.append(f'supportedInterfaces[{i}].protocolBinding must be JSONRPC, GRPC, or HTTP+JSON, got: {binding}')162if not card.get('supportedInterfaces'):163 errors.append('supportedInterfaces must have at least one entry')164165# Step 4: Validate skills entries166SKILL_REQUIRED = ['id', 'name', 'description', 'tags']167for i, skill in enumerate(card.get('skills', [])):168 for field in SKILL_REQUIRED:169 if field not in skill:170 errors.append(f'skills[{i}] missing required field: {field}')171 if 'tags' in skill and not isinstance(skill['tags'], list):172 errors.append(f'skills[{i}].tags must be an array')173174# Step 5: Validate defaultInputModes/defaultOutputModes are non-empty175if not card.get('defaultInputModes'):176 errors.append('defaultInputModes must have at least one entry')177if not card.get('defaultOutputModes'):178 errors.append('defaultOutputModes must have at least one entry')179180# Step 6: Validate provider if present181if 'provider' in card and card['provider'] is not None:182 for field in ('organization', 'url'):183 if field not in card['provider']:184 errors.append(f'provider missing required field: {field}')185186# Step 7: Report results187if errors:188 print(f'FAIL: {len(errors)} validation error(s):')189 for e in errors:190 print(f' - {e}')191 sys.exit(1)192else:193 skill_count = len(card.get('skills', []))194 iface_count = len(card.get('supportedInterfaces', []))195 print(f'PASS: All mandatory fields present ({iface_count} interface(s), {skill_count} skill(s))')196"197```198199Replace `<OUTPUT_FILE_PATH>` with the actual path of the generated JSON file.200201If validation fails, fix the errors in the JSON and re-run validation until all checks pass. Do NOT report success to the user until validation passes.202203### 8. Report results204205After validation passes, output results in EXACTLY this format:206207```208Validation passed. Here's a summary of the generated agent card:209210Output file: <filename>.json211212Detected from code:213214- Agent name: <AgentName> (from <how it was detected, e.g. Strands agent with BedrockAgentCoreApp>)215- Skills: <count> - <skill_id> (<brief description>), <skill_id> (<brief description>), ...216- Protocol: <HTTP+JSON or JSONRPC> (<why, e.g. uses BedrockAgentCoreApp on port 8080>)217- Auth: <auth mechanisms detected, e.g. IAM/SigV4 (default) + Cognito JWT (optional)>218- Streaming: <true or false>219- Endpoint URL: <source, e.g. From .bedrock_agentcore.yaml - uses the my_agent deployment ARN (account ..., region ...)> or <Placeholder used - no deployment config found>220```221222If validation fails, show the errors first, fix them, re-validate, and only show the summary above after all checks pass.223224## Reference template225226Use this as a structural reference (from simple-a2a-agent):227228```json229{230 "name": "SimpleCalculatorAgent",231 "description": "A simple calculator agent that can evaluate mathematical expressions.",232 "version": "1.0.0",233 "supportedInterfaces": [234 {235 "url": "https://bedrock-agentcore.us-east-1.amazonaws.com/runtimes/<encoded-arn>/invocations/",236 "protocolBinding": "JSONRPC",237 "protocolVersion": "1.0"238 }239 ],240 "capabilities": {241 "streaming": true,242 "pushNotifications": false243 },244 "defaultInputModes": ["text/plain"],245 "defaultOutputModes": ["text/plain"],246 "skills": [247 {248 "id": "calculator",249 "name": "Calculator",250 "description": "Evaluate a mathematical expression and return the result.",251 "tags": ["math", "calculator", "arithmetic"],252 "examples": [253 "What is 42 * 17?",254 "Calculate the square root of 144",255 "What is 15% of 200?"256 ]257 }258 ]259}260```