Developer guidesAbilities for AI agents

Abilities for AI agents

Let an AI agent list, add and remove icons through WordPress abilities: what each ability takes and returns, how it is gated, and how to call it.

WordPress 6.9 added the Abilities API: a plugin describes what it can do, with an input and output schema, and AI tools can discover and run those abilities through REST or an MCP adapter. Easy SVG Pro registers four of them. An agent can read every icon on the site, add a new one to the icon library, and add or remove icons in an icon set. Every icon it writes goes through the same sanitizer an upload meets.

The four abilities

AbilityWhat it doesWrites?REST method
easy-svg-pro/list-iconsLists icons from the library, collections and sets, pagedNoGET
easy-svg-pro/add-iconAdds one icon to the free icon libraryYes, never overwritesPOST
easy-svg-pro/add-icons-to-setAdds icons to an existing icon setYes, never overwritesPOST
easy-svg-pro/remove-icon-from-setRemoves icons from a set by nameYes, no undoDELETE

All four sit in the category easy-svg-pro, labelled "Easy SVG".

When they exist

An agent sees the abilities only when all of this is true:

WordPress has the Abilities API

WordPress 6.9 or newer. On older versions nothing is registered and nothing breaks.

The licence is active and the feature is on

Turn on AI agent abilities under Icons → Features, in the group For developers. It has its own switch on purpose: an agent that can write icons should be a decision, not a side effect.

The set abilities also need the set editor

add-icons-to-set and remove-icon-from-set refuse with easy_svg_pro_no_editor (HTTP 409) unless Icon set editor is on as well.

The user may manage options

Every ability's permission check requires manage_options. An agent with an application password acts as that WordPress user, with that user's capabilities.

Which icons list-icons reports also depends on features: the free library only while its icons feature is on in the free plugin, collections from themes, folders and code only while Multiple collections is on, and sets only while Icon set editor is on.

Calling them over REST

WordPress serves abilities under /wp-json/wp-abilities/v1/. Authenticate with an application password of an administrator. WordPress only offers application passwords over HTTPS, or on a site whose environment type is local.

export SITE="https://example.com"
export AUTH="agent-bot:abcd efgh ijkl mnop qrst uvwx"

# What can this site do?
curl -s -u "$AUTH" "$SITE/wp-json/wp-abilities/v1/abilities?category=easy-svg-pro"

The run endpoint is /wp-json/wp-abilities/v1/abilities/<name>/run. WordPress picks the HTTP method from each ability's annotations: read only abilities run with GET, destructive and idempotent ones with DELETE, everything else with POST. For GET and DELETE the input goes in the input query parameter; for POST it goes in the JSON body under input.

List icons

curl -s -u "$AUTH" -G "$SITE/wp-json/wp-abilities/v1/abilities/easy-svg-pro/list-icons/run" \
	--data-urlencode "input[search]=arrow" \
	--data-urlencode "input[per_page]=50"
{
	"items": [
		{ "slug": "arrow-right", "label": "Arrow Right", "collection": "acme", "source": "set" }
	],
	"total": 1,
	"page": 1,
	"per_page": 50,
	"has_more": false,
	"truncated": false
}

Input fields:

FieldTypeDefaultMeaning
sourceall, library, collection, setallWhich kind of source to read
collectionstringnoneOnly this collection or set slug
searchstringnoneCase insensitive match on slug and label
include_markupbooleanfalseAdd each icon's sanitized SVG markup
pageinteger, 1 or more1Page number
per_pageinteger, 1 to 500100Icons per page

Add an icon to the library

curl -s -u "$AUTH" -X POST "$SITE/wp-json/wp-abilities/v1/abilities/easy-svg-pro/add-icon/run" \
	-H "Content-Type: application/json" \
	-d '{"input":{"label":"Arrow","markup":"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M5 12h14"/></svg>"}}'
{ "added": true, "slug": "arrow-2", "label": "Arrow", "collection": "easy-svg", "source": "library" }

A name that is taken gets a number. The slug in the answer is the one WordPress really stored, read back after the write. Use it, never one you derived from the label yourself.

Add icons to a set

icons is an object keyed by the name each icon should get. Each value carries label and markup.

curl -s -u "$AUTH" -X POST "$SITE/wp-json/wp-abilities/v1/abilities/easy-svg-pro/add-icons-to-set/run" \
	-H "Content-Type: application/json" \
	-d '{"input":{"set_id":42,"icons":{"cart":{"label":"Cart","markup":"<svg ...>...</svg>"}}}}'
{ "set_id": 42, "slug": "acme", "report": [ { "slug": "cart", "state": "added" } ] }

A name the set already holds is reported as exists and left alone; the ability has no way to overwrite. slug is the collection slug templates use, for example acme/cart.

Remove icons from a set

curl -s -u "$AUTH" -X DELETE -G "$SITE/wp-json/wp-abilities/v1/abilities/easy-svg-pro/remove-icon-from-set/run" \
	--data-urlencode "input[set_id]=42" \
	--data-urlencode "input[slugs][]=cart"
{ "set_id": 42, "slug": "acme", "report": [ { "slug": "cart", "state": "removed" } ] }

A name the set does not hold comes back as not_found; the others are still removed.

Calling them from PHP

Abilities are plain WordPress objects, so your own code can run them too, for example from a queue worker that processes requests an agent left in a table.

/**
 * Add one icon to the library through the ability, with every check it applies.
 */
function acme_agent_add_icon( $label, $markup ) {
	if ( ! function_exists( 'wp_get_ability' ) ) {
		return new WP_Error( 'acme_no_abilities', 'This WordPress has no Abilities API.' );
	}

	$ability = wp_get_ability( 'easy-svg-pro/add-icon' );
	if ( null === $ability ) {
		return new WP_Error( 'acme_no_ability', 'Turn on AI agent abilities under Icons, Features.' );
	}

	$result = $ability->execute(
		array(
			'label'  => (string) $label,
			'markup' => (string) $markup,
		)
	);

	if ( is_wp_error( $result ) ) {
		error_log( sprintf( 'Icon refused: %s (%s)', $result->get_error_message(), $result->get_error_code() ) );
	}

	return $result;
}

execute() validates the input against the schema and runs the permission check, so it needs a current user with manage_options. If this code runs outside a REST request and writes sets, also add easy_svg_pro_set_write_context so it takes the set lock.

Errors an agent should understand

Every refusal is a WP_Error with a stable code, so a client can branch on it.

CodeHTTPMeaning
easy_svg_pro_missing_label, easy_svg_pro_missing_markup400Required input missing
easy_svg_pro_missing_set_id, easy_svg_pro_missing_icons, easy_svg_pro_missing_slugs400Required set input missing
easy_svg_pro_bad_name422The label cannot become an icon name
easy_svg_pro_not_svg422The sanitizer did not accept it as SVG
easy_svg_pro_empty422Nothing drawable was left
easy_svg_pro_too_large422Larger than the site's size limit; the message and max_mb name it
easy_svg_pro_too_complex422Too many parts to read safely
easy_svg_pro_no_store409Icon library off, or the free plugin too old
easy_svg_pro_no_editor409Icon set editor off
easy_svg_pro_no_sanitizer, easy_svg_pro_not_saved500Server side problem, nothing stored

Pitfalls

  • list-icons does not return set IDs. The set abilities need set_id, but list-icons reports sets by slug only. Look the ID up yourself, for example with GET /wp-json/easy-svg-pro/v1/sets/list (internal route) or in the Icon Sets tab, and give it to the agent.
  • Set slugs in list-icons are post slugs. On sites that ran older versions a set's registered collection may be acme-x while list-icons says acme. The set abilities answer the registered slug.
  • The same icon twice. With Multiple collections and Icon set editor both on, a set's icons appear once with source: collection and once with source: set. Filter by source when you count.
  • An unknown source returns nothing. A typo such as sets gives an empty list, not everything. That is deliberate.
  • Refused icons are not in the report. In add-icons-to-set, an icon the sanitizer refuses is dropped before the merge and simply does not appear in report. Compare the names you sent with the names you got back.
  • An unknown set does not fail. add-icons-to-set and remove-icon-from-set with a set_id that is not an icon set answer with an empty slug and an empty report instead of an error. Treat an empty slug as failure.
  • No size cap per call. The REST route behind the set abilities takes at most 25 icons; the abilities do not apply that cap. Send reasonable batches anyway.
  • MCP needs an adapter. The abilities carry mcp metadata, but Easy SVG Pro does not ship an MCP server. Check the key names against the adapter your site runs.

Give agents their own WordPress user and their own application password, and revoke it when the project ends. manage_options is a strong capability: the same password can change every setting on the site, not only icons.