WSO2 Agent Onboarding
WSO2 Agent Onboarding — automated agent self-registration on WSO2 API Manager. Uses WSO2's native Dynamic Client Registration endpoint (RFC 7591) for client provisioning, composes Devportal application + per-API key-generation operations, attaches throttling policies as scope tiers, and observes audit via the tenant-logs surface (native, no side-channel). Runtime policy enforcement (signature verify, consent check, scope classify, audit emit) lives in the orchestration.steps below — each step that gates issuance carries on_failure: deny. Lint-time validation of this capability shape lives in the companion Polychro ruleset at https://github.com/api-evangelist/posts/blob/main/polychro/agent-onboarding-rules.yaml — Polychro is Naftiko's governance layer, separate from the capability spec, and is the correct home for cross-object consistency rules that apply across every agent-onboarding capability.
What You Can Do
MCP Tools
agent-register
agent-revoke
Capability Spec
naftiko: 1.0.0-alpha2
info:
label: WSO2 Agent Onboarding
description: 'WSO2 Agent Onboarding — automated agent self-registration on WSO2 API Manager.
Uses WSO2''s native Dynamic Client Registration endpoint (RFC 7591) for client provisioning,
composes Devportal application + per-API key-generation operations, attaches throttling policies
as scope tiers, and observes audit via the tenant-logs surface (native, no side-channel). Runtime policy enforcement (signature verify, consent check, scope classify, audit emit) lives in the orchestration.steps below — each step that gates issuance carries on_failure: deny. Lint-time validation of this capability shape lives in the companion Polychro ruleset at https://github.com/api-evangelist/posts/blob/main/polychro/agent-onboarding-rules.yaml — Polychro is Naftiko''s governance layer, separate from the capability spec, and is the correct home for cross-object consistency rules that apply across every agent-onboarding capability.'
tags:
- WSO2
- Agent Onboarding
- Dynamic Client Registration
- RFC 7591
- Web Bot Auth
- Per-API Keys
- MCP
- Naftiko Capability
created: '2026-05-28'
modified: '2026-05-28'
related:
- https://apievangelist.com/2026/05/27/automated-agent-onboarding-is-a-naftiko-capability-not-a-gateway-feature/
- https://github.com/api-evangelist/wso2
binds:
- namespace: env
keys:
WSO2_BASE_URI: WSO2_BASE_URI
WSO2_ADMIN_TOKEN: WSO2_ADMIN_TOKEN
WSO2_TENANT: WSO2_TENANT
AGENT_TRUSTED_ISSUERS: AGENT_TRUSTED_ISSUERS
AGENT_CONSENT_HASH: AGENT_CONSENT_HASH
capability:
consumes:
- type: http
namespace: wso2-dcr
baseUri: '{{env.WSO2_BASE_URI}}/client-registration/v0.17'
description: WSO2 Dynamic Client Registration — the RFC 7591 endpoint that already exists
natively as the closest match to an agent-registration surface in the gateway field.
resources:
- name: register
path: /register
operations:
- name: registerclient
method: POST
description: Register the agent as an OAuth client. Returns clientId + clientSecret
plus the software_statement echo.
outputRawFormat: json
outputParameters:
- { name: result, type: object, value: $. }
inputParameters:
- { name: body, in: body, type: object, required: true }
authentication:
type: bearer
token: '{{env.WSO2_ADMIN_TOKEN}}'
- type: http
namespace: wso2-devportal
baseUri: '{{env.WSO2_BASE_URI}}/api/am/devportal/v3'
description: WSO2 Devportal API — applications + per-API keys + subscriptions + MCP servers.
resources:
- name: applications
path: /applications
operations:
- name: createapplication
method: POST
description: Create the agent's application entity (the credential container).
outputRawFormat: json
outputParameters:
- { name: result, type: object, value: $. }
inputParameters:
- { name: body, in: body, type: object, required: true }
- name: app-subscriptions
path: /subscriptions
operations:
- name: createsubscription
method: POST
description: Subscribe the application to the requested API with a throttling policy
attached (the scope tier).
outputRawFormat: json
outputParameters:
- { name: result, type: object, value: $. }
inputParameters:
- { name: body, in: body, type: object, required: true }
- name: api-keys-generate
path: /apis/{apiId}/api-keys/generate
operations:
- name: generateapikey
method: POST
description: Mint a per-API key for the agent — WSO2's unique affordance, one credential
per API rather than one credential covering many APIs.
outputRawFormat: json
outputParameters:
- { name: result, type: object, value: $. }
inputParameters:
- { name: apiId, in: path, type: string, required: true }
- { name: body, in: body, type: object, required: true }
- name: mcp-servers
path: /mcp-servers
operations:
- name: getallmcpservers
method: GET
description: Enumerate the MCP servers WSO2 already configures — used by the worker
to populate /.well-known/mcp without any custom discovery code.
outputRawFormat: json
outputParameters:
- { name: result, type: object, value: $. }
authentication:
type: bearer
token: '{{env.WSO2_ADMIN_TOKEN}}'
- type: http
namespace: wso2-devops
baseUri: '{{env.WSO2_BASE_URI}}/api/am/devops/v0'
description: WSO2 Devops API — tenant-logs for native audit observation. The Web Bot Auth
signature surfaces here without any side-channel because WSO2 emits audit on the same
gateway estate as the credential issuance.
resources:
- name: tenant-logs-apis
path: /tenant-logs/{tenant}/apis
operations:
- name: gettenantapilogs
method: GET
description: Read the tenant-level API audit stream for observing agent traffic.
outputRawFormat: json
outputParameters:
- { name: result, type: object, value: $. }
inputParameters:
- { name: tenant, in: path, type: string, required: true }
authentication:
type: bearer
token: '{{env.WSO2_ADMIN_TOKEN}}'
orchestration:
- name: onboard-agent
description: Verify signature, DCR-register the agent as a client, create application,
subscribe to requested API with throttling policy, generate per-API key, observe audit.
inputs:
- { name: signature, type: object, required: true }
- { name: signature_agent, type: string, required: true }
- { name: skill_id, type: string, required: true }
- { name: requested_scopes, type: array, required: true, description: 'Each scope identifies one apiId.' }
- { name: consent_hash, type: string, required: true }
- { name: contact, type: object, required: true }
steps:
- id: verify_signature
type: builtin.web-bot-auth.verify
with:
signature: '${input.signature}'
agent: '${input.signature_agent}'
trusted_issuers: '{{env.AGENT_TRUSTED_ISSUERS}}'
on_failure: deny
- id: verify_consent
type: builtin.policy.assert
with:
assert: '${input.consent_hash} == {{env.AGENT_CONSENT_HASH}}'
on_failure: deny
- id: classify_scopes
type: builtin.policy.scope-classify
with:
requested: '${input.requested_scopes}'
- id: dcr_register
call: wso2-dcr.registerclient
description: Translate Web Bot Auth signature into a DCR registration. The
software_statement JWT carries the operator + agent identity claims.
with:
body:
client_name: 'agent-${steps.verify_signature.agent_id}'
owner: '${input.contact.operator}'
grant_types: ['client_credentials']
tokenType: JWT
callback_url: ''
- id: create_application
call: wso2-devportal.createapplication
with:
body:
name: 'agent-app-${steps.verify_signature.agent_id}'
throttlingPolicy: '${steps.classify_scopes.target}'
description: 'Auto-created by Naftiko agent-onboarding capability'
tokenType: JWT
attributes:
operator: '${input.contact.operator}'
skill_id: '${input.skill_id}'
- id: subscribe_and_mint
type: builtin.for-each
description: For each requested API scope, subscribe the application and mint
a per-API key (WSO2's strongest affordance).
with:
items: '${steps.classify_scopes.auto}'
do:
- id: subscribe
call: wso2-devportal.createsubscription
with:
body:
apiId: '${item.apiId}'
applicationId: '${steps.create_application.applicationId}'
throttlingPolicy: '${steps.classify_scopes.target}'
- id: mint
call: wso2-devportal.generateapikey
with:
apiId: '${item.apiId}'
body:
validityPeriod: 2592000
additionalProperties: {}
- id: emit_audit
type: builtin.audit.emit
description: WSO2 emits audit natively on tenant-logs; the orchestration tags
the application + subscriptions so the audit stream is queryable by agent_id.
with:
target: wso2-devops.gettenantapilogs
annotate_with:
agent_id: '${steps.verify_signature.agent_id}'
operator: '${input.contact.operator}'
consent_hash: '${input.consent_hash}'
signature_keyid: '${steps.verify_signature.keyid}'
output:
agent_id: '${steps.verify_signature.agent_id}'
client_id: '${steps.dcr_register.clientId}'
application_id: '${steps.create_application.applicationId}'
credentials: '${steps.subscribe_and_mint.results}'
scope_tier: '${steps.classify_scopes.target}'
- name: revoke-agent
description: Revoke all per-API keys held by the agent's application.
inputs:
- { name: application_id, type: string, required: true }
steps:
- id: delete_app
description: Deleting the application revokes all per-API keys attached to it.
type: builtin.delete
with:
target: wso2-devportal.applications
id: '${input.application_id}'
output:
revoked: true
exposes:
- type: rest
namespace: wso2-agent-onboarding-rest
port: 8080
resources:
- path: /v1/agents/onboard
operations:
- method: POST
name: onboardagent
call: orchestration.onboard-agent
- path: /v1/agents/{agent_id}/revoke
operations:
- method: POST
name: revokeagent
call: orchestration.revoke-agent
- type: mcp
namespace: wso2-agent-onboarding-mcp
port: 9090
transport: http
tools:
- name: agent-register
hints: { readOnly: false, destructive: false, idempotent: false }
call: orchestration.onboard-agent
- name: agent-revoke
hints: { readOnly: false, destructive: true, idempotent: true }
call: orchestration.revoke-agent
- type: agent-skill
namespace: wso2-agent-onboarding-skill
description: 'Agent skill at /skills/onboard-agent.md. WSO2-specific addendum: per-API
keys mean the agent receives an array of credentials, one per requested API, rather
than one credential covering many APIs.'
skill:
name: onboard-agent
file: skills/onboard-agent.md