WSO2 · Capability

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.

Run with Naftiko WSO2Agent OnboardingDynamic Client RegistrationRFC 7591Web Bot AuthPer-API KeysMCPNaftiko Capability

What You Can Do

POST
Onboardagent
/v1/agents/onboard
POST
Revokeagent
/v1/agents/{agent_id}/revoke

MCP Tools

agent-register

agent-revoke

idempotent

Capability Spec

wso2-agent-onboarding.yaml Raw ↑
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