Skip to content

A2A Agent Management Guide

This guide covers registering, managing, and using A2A agents through the MCP Gateway Registry using the mcp-gateway-m2m service account.

Quick Start

Service Account: mcp-gateway-m2m

All agent management operations use the mcp-gateway-m2m Keycloak M2M service account:

# Register an agent (uses mcp-gateway-m2m token automatically)
uv run python cli/agent_mgmt.py register cli/examples/code_reviewer_agent.json

# List agents
uv run python cli/agent_mgmt.py list

# Get agent details
uv run python cli/agent_mgmt.py get /code-reviewer

# Test agent (verify registry metadata and endpoint accessibility)
uv run python cli/agent_mgmt.py test /code-reviewer

# Test all agents
uv run python cli/agent_mgmt.py test-all

# Search agents (semantic search by capability)
uv run python cli/agent_mgmt.py search "code review agent"

# Update agent
uv run python cli/agent_mgmt.py update /code-reviewer cli/examples/code_reviewer_agent.json

# Toggle agent enabled/disabled status
uv run python cli/agent_mgmt.py toggle /code-reviewer true   # Enable
uv run python cli/agent_mgmt.py toggle /code-reviewer false  # Disable

# Delete agent
uv run python cli/agent_mgmt.py delete /code-reviewer

Token Details: - File: .oauth-tokens/ingress.json (auto-loaded by CLI) - Generated by: ./credentials-provider/generate_creds.sh - Keycloak Groups: mcp-servers-unrestricted, a2a-agent-admin - Permissions: Full agent management (register, modify, delete, list)

Service Account Details

Account Identity

Property Value
Keycloak Client ID mcp-gateway-m2m
Service Account User service-account-mcp-gateway-m2m
Token File .oauth-tokens/ingress.json
Token Generator ./credentials-provider/generate_creds.sh

Keycloak Groups (Auto-Assigned)

  • mcp-servers-unrestricted - Full access to unrestricted MCP servers
  • a2a-agent-admin - Full A2A agent management permissions

Permissions

  • ✅ Register agents
  • ✅ Modify agents
  • ✅ Delete agents
  • ✅ List agents
  • ✅ Manage MCP server groups

Authentication Flow

1. CLI loads token from .oauth-tokens/ingress.json
   └─ JWT contains: groups: ["mcp-servers-unrestricted", "a2a-agent-admin"]

2. POST /api/agents/register with Authorization: Bearer <token>

3. Nginx /api/ location intercepts request
   └─ Calls auth-server /validate endpoint

4. Auth-server validates JWT and maps groups to scopes
   └─ Returns: X-Scopes: a2a-agent-admin

5. Nginx forwards request to FastAPI with X-Scopes header

6. FastAPI reads X-Scopes and grants permissions
   └─ Detects a2a-agent-admin → allows agent registration

7. Agent is registered successfully

Agent Examples

Register Code Reviewer Agent

uv run python cli/agent_mgmt.py register cli/examples/code_reviewer_agent.json

Available examples: - code_reviewer_agent.json - Code quality analysis - test_automation_agent.json - Test case generation and execution - data_analysis_agent.json - Statistical analysis and visualization - security_analyzer_agent.json - Vulnerability detection - documentation_agent.json - API documentation generation - devops_deployment_agent.json - Infrastructure automation

Create Custom Agent

  1. Copy example file:

    cp cli/examples/code_reviewer_agent.json cli/examples/my_agent.json
    

  2. Edit JSON with your agent details:

    {
      "name": "My Agent",
      "path": "/my-agent",
      "description": "What my agent does",
      "url": "http://my-domain.com/agents/my-agent",
      "version": "1.0.0",
      "protocol_version": "1.0",
      "visibility": "public",
      "trust_level": "community",
      "tags": ["custom"],
      "security_schemes": {
        "bearer": {
          "type": "bearer"
        }
      }
    }
    

  3. Register:

    uv run python cli/agent_mgmt.py register cli/examples/my_agent.json
    

Verification

Check Token Has Correct Groups

python3 << 'EOF'
import json, base64
with open('.oauth-tokens/ingress.json') as f:
    token = json.load(f)['access_token']
payload = token.split('.')[1]
payload += '='*(4-len(payload)%4)
decoded = json.loads(base64.urlsafe_b64decode(payload))
print("Service Account:", decoded.get('client_id'))
print("Groups:", decoded.get('groups'))
print("Expected groups: ['mcp-servers-unrestricted', 'a2a-agent-admin']")
EOF

Expected output:

Service Account: mcp-gateway-m2m
Groups: ['mcp-servers-unrestricted', 'a2a-agent-admin']
Expected groups: ['mcp-servers-unrestricted', 'a2a-agent-admin']

Check Auth Server Sees Groups

TOKEN=$(python3 -c "import json; print(json.load(open('.oauth-tokens/ingress.json'))['access_token'])")
curl -s "http://localhost:8888/validate" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Original-URL: http://localhost/agents/register" | \
  python3 -m json.tool | grep -E "groups|scopes"

Expected output should include:

"groups": ["mcp-servers-unrestricted", "a2a-agent-admin"],
"scopes": [..., "a2a-agent-admin", ...]

Troubleshooting

Issue: "Authentication required" Error

Check 1: Token file exists

[ -f .oauth-tokens/ingress.json ] && echo "✓ Token exists" || echo "✗ Token missing"

Check 2: Token has groups

python3 << 'EOF'
import json, base64
with open('.oauth-tokens/ingress.json') as f:
    token = json.load(f)['access_token']
payload = token.split('.')[1] + '='*(4-len(token.split('.')[1])%4)
decoded = json.loads(base64.urlsafe_b64decode(payload))
groups = decoded.get('groups', [])
print(f"Groups in token: {groups}")
if 'a2a-agent-admin' not in groups:
    print("✗ Missing a2a-agent-admin - try refreshing token:")
    print("  ./credentials-provider/generate_creds.sh")
EOF

Check 3: Auth server sees groups

TOKEN=$(python3 -c "import json; print(json.load(open('.oauth-tokens/ingress.json'))['access_token'])")
curl -s "http://localhost:8888/validate" -H "Authorization: Bearer $TOKEN" | \
  python3 -m json.tool | grep groups

Should show: "groups": ["mcp-servers-unrestricted", "a2a-agent-admin"]

Check 4: Nginx forwards scopes

curl -v http://localhost/api/agents/register \
  -X POST \
  -H "Authorization: Bearer $(python3 -c 'import json; print(json.load(open(\".oauth-tokens/ingress.json\"))[\"access_token\"])')" \
  2>&1 | grep -i x-scopes

Should include: x-scopes: a2a-agent-admin (note: uses port 80 via Nginx, not direct application port)

Solution: Refresh Token

If token is missing groups, regenerate it:

./credentials-provider/generate_creds.sh

Then verify groups reappear:

python3 << 'EOF'
import json, base64
with open('.oauth-tokens/ingress.json') as f:
    token = json.load(f)['access_token']
payload = token.split('.')[1] + '='*(4-len(token.split('.')[1])%4)
decoded = json.loads(base64.urlsafe_b64decode(payload))
print("Groups:", decoded.get('groups'))
EOF

JWT Token Structure

The mcp-gateway-m2m service account's JWT token contains:

{
  "exp": 1761942660,
  "iat": 1761942360,
  "iss": "http://localhost:8080/realms/mcp-gateway",
  "sub": "user-id-uuid",
  "typ": "Bearer",
  "azp": "mcp-gateway-m2m",
  "client_id": "mcp-gateway-m2m",
  "preferred_username": "service-account-mcp-gateway-m2m",
  "groups": ["mcp-servers-unrestricted", "a2a-agent-admin"],
  "scope": "profile email mcp-servers-restricted/execute mcp-servers-restricted/read mcp-servers-unrestricted/read mcp-servers-unrestricted/execute a2a-agent-admin"
}

Key fields: - client_id: mcp-gateway-m2m - identifies the service account - groups: List of Keycloak groups the account belongs to - scope: Space-separated list of OAuth2 scopes for authorization - a2a-agent-admin: The scope that grants agent management permissions

Setup (Automatic During Initialization)

The mcp-gateway-m2m service account is automatically configured during Keycloak initialization:

  1. Keycloak Client Created - mcp-gateway-m2m M2M client registered
  2. Service Account User Created - service-account-mcp-gateway-m2m user created
  3. Groups Assigned - User assigned to mcp-servers-unrestricted and a2a-agent-admin groups
  4. Groups Mapper Added - JWT tokens include groups claim
  5. Auth Scopes Configured - Groups mapped to OAuth2 scopes in auth_server/scopes.yml
  6. Nginx Protected - /api/* endpoints require JWT authentication

No manual configuration needed - everything is automatic!

Initialization Files

These files are involved in the automatic setup:

File Purpose
keycloak/setup/init-keycloak.sh Creates groups, assigns M2M to groups, adds groups mapper
auth_server/scopes.yml Maps groups to scopes
docker/nginx_rev_proxy_http_only.conf Protects /api/ endpoints with authentication
credentials-provider/generate_creds.sh Generates fresh JWT tokens

Environment Variables

The token generation process uses these environment variables from .env:

# Keycloak Configuration
KEYCLOAK_URL=http://localhost:8080
KEYCLOAK_REALM=mcp-gateway
KEYCLOAK_ADMIN=admin
KEYCLOAK_ADMIN_PASSWORD=SecureKeycloakAdmin123!

# M2M Client Credentials (set by init script)
KEYCLOAK_M2M_CLIENT_ID=mcp-gateway-m2m
KEYCLOAK_M2M_CLIENT_SECRET=<generated>

Common Tasks

Register Multiple Agents

# Create multiple agent files
cp cli/examples/code_reviewer_agent.json cli/examples/reviewer.json
cp cli/examples/test_automation_agent.json cli/examples/tester.json

# Register each
uv run python cli/agent_mgmt.py register cli/examples/reviewer.json
uv run python cli/agent_mgmt.py register cli/examples/tester.json

# List all
uv run python cli/agent_mgmt.py list

Update Agent Configuration

# Modify the agent JSON file
vi cli/examples/my_agent.json

# Re-register to update (will overwrite)
uv run python cli/agent_mgmt.py register cli/examples/my_agent.json

Remove Agent

uv run python cli/agent_mgmt.py delete /my-agent

Test Agent Availability

# Test that agent is accessible
uv run python cli/agent_mgmt.py test /code-reviewer

# If successful:
# ✓ Agent registered
# ✓ Endpoint is reachable
# ✓ Agent is responding

FAQ

Q: What if I get "Agent already exists" error? A: The agent is already registered. Either delete it first or change the path in your JSON.

Q: Where are agents stored? A: In the registry database. Agent metadata is stored at registry/agents/ during development.

Q: Can I use a different service account? A: No, mcp-gateway-m2m is the configured M2M account for all CLI operations. Create separate accounts only if needed for different purposes.

Q: How often should I refresh the token? A: Automatically via ./credentials-provider/generate_creds.sh which is called by the shell startup. Manual refresh only needed if token expires.

Q: What if the token expires? A: Run ./credentials-provider/generate_creds.sh to get a fresh token.

Q: Can agents be private? A: Yes, set "visibility": "private" in agent JSON. Only registered users can access private agents.

Getting Help

  1. Check Troubleshooting section above
  2. Review JWT token contents and verify groups are present
  3. Check service is running: docker-compose ps
  4. View logs: docker logs mcp-gateway-registry-auth-server-1
  5. Verify Keycloak groups in admin UI: http://localhost:8080/admin

Summary

  • Service Account: mcp-gateway-m2m (auto-created during init)
  • Token File: .oauth-tokens/ingress.json (auto-loaded by CLI)
  • Permissions: Full agent management (register, modify, delete, list)
  • Groups: mcp-servers-unrestricted, a2a-agent-admin (auto-assigned)
  • Setup: Fully automatic - no manual configuration needed