Agent abilities

WordPress 7.1 ships the Abilities API: a register of named jobs a site can do, each with a typed input schema, a description written for a reader, and a capability check. An AI assistant that can reach your site — through the REST API, or through an MCP server that exposes the register — can call them instead of guessing at your database.

The companion plugin registers nineteen, in the category table-and-type-core. They cover the jobs an owner repeats: the card, the services, the hours, the slips, the booking settings, the site facts and the coffee programme.

Two properties are attached to each so a caller knows what it is doing before it does it: readonly (it changes nothing), idempotent (calling it twice does the same as calling it once) and destructive (something goes away).

The card

Ability Verb What it does
table-and-type-core/list-menu-items GET, readonly, idempotent Every dish, or the dishes of one service or one section. Returns each dish with its id, its price already formatted, its marks, its sections and the services it is served at. Call it first, so you write ids that exist.
table-and-type-core/add-menu-item POST Creates a published dish. A section named but not yet on the site is created with it. Returns the new record.
table-and-type-core/update-menu-item POST, idempotent Changes only the fields you pass, and returns the record as it was and as it is now.
table-and-type-core/delete-menu-item DELETE, destructive, idempotent Moves the dish to the bin, where it can be restored. Nothing is erased. To take a dish off the card for a while, set its availability to off instead.
table-and-type-core/list-dayparts GET, readonly, idempotent Every service with its slug, its days, its hours and whether it takes bookings, plus what is being served right now.
table-and-type-core/update-daypart POST, idempotent Changes a service's days, hours, labels or booking rule. Every derived sentence on the site follows: the open status, the hero clause and the laptop rule are read from this record, never typed.

The hours

Ability Verb What it does
table-and-type-core/get-hours GET, readonly, idempotent Every row — the seven days, the terrace, anything else — with its key, its label, what it says and whether it reads as closed, plus the derived open sentence for right now.
table-and-type-core/update-hours POST, idempotent Writes one or more rows by key, and returns what each said before and after. An empty value means closed. A key the record does not have is added as a new row at the end. Only the rows you pass change.

There is deliberately no delete: an empty value already means closed, and an agent that could delete Thursday could leave a week with six lines in it.

The slips

Ability Verb What it does
table-and-type-core/list-slips GET, readonly, idempotent The dated slips, with the card each is clipped to, its window, its lines and whether it is live, expired or still to come. Filter by state, kind or target.
table-and-type-core/post-slip POST Clips a dated slip to a card. It runs the same five checks the editor does and refuses the same shapes. On a refusal nothing is saved and the message says what would have gone wrong on the page.
table-and-type-core/expire-slip POST, idempotent Closes a slip's window now, so it stops showing and the card underneath is the truth again. Nothing is deleted — the record and its revisions stay, which is how a café can see what it served last Tuesday.

Booking

Ability Verb What it does
table-and-type-core/list-booking-rows GET, readonly, idempotent One row per bookable service — its id, the service, its label, the policy sentence a reader sees, its position, and whether a live slip is striking it.
table-and-type-core/update-booking-row POST, idempotent Changes one booking row. A service that does not take bookings is refused, with the list of the ones that do — because a row naming it would tell a reader they can book something they cannot.
table-and-type-core/get-booking-settings GET, readonly, idempotent How bookings are taken (link, provider or none, with the page, the partner and the ids), the party limit, the group threshold, the hold, the voucher sentence, where enquiries go and whether a copy is kept — and the same for takeaway orders.
table-and-type-core/update-booking-settings POST, idempotent Merges what you pass and returns previous and new. Setting the mode to provider makes the site load a reservation partner's script in visitors' browsers, which is the one third-party request the site otherwise never makes — say so in the privacy notice when you do.

The site facts

Ability Verb What it does
table-and-type-core/get-site-facts GET, readonly, idempotent Every site fact — address, contact, clock and whatever the enabled parts of the plugin add — with the schema each one is saved against. Pass a dot path such as address.city for one fact. Call it before updating, so you write keys that exist.
table-and-type-core/update-site-facts POST, idempotent Merges the facts you pass into the saved ones and returns previous and new. Only the keys you pass change; a key the schema does not know is dropped.

These two reach Settings › Site details as a whole, so they are the way an assistant edits the address, the coordinates, the tax note, the house rules, the privacy record or the clock. They need manage_options — the capability that screen itself asks for — rather than edit_posts.

The coffee programme and the bakes

Ability Verb What it does
table-and-type-core/get-grinder GET, readonly, idempotent The two coffees on today — roaster, origin, process and the date each went on — and what is out of the oven with its batch times.
table-and-type-core/update-grinder POST, idempotent Changes the coffee on today, the plate beside it, or the list of bakes, and returns previous and new. Only what you pass changes; passing bakes replaces the whole list.

espresso and filter each take roaster, origin, process and since (a date written 2026-09-08), plus plate — an attachment id — and plate_focal with x and y between 0 and 1. A bake is name (or item_id, a dish you already have), batches and usually_gone.

How an assistant calls them

Every write returns the previous record as well as the new one, so an assistant can show you what it changed and undo it without a second read.

Three rules the register enforces, worth knowing when you are debugging a call:

Over REST

Abilities are exposed under the Abilities API's own REST namespace on your site, and every one of the underlying records is also at /wp-json/wp/v2/tat_menu_item, …/tat_slip and so on. Both paths need an authenticated user — an application password is the usual way.

POST /wp-json/wp/v2/tat_slip
Authorization: Basic <user:application-password>
Content-Type: application/json

{
  "status": "publish",
  "meta": {
    "tat_kind": "special",
    "tat_target_type": "daypart",
    "tat_target_id": "midi",
    "tat_valid_from": "2026-09-18T07:52:00",
    "tat_valid_to":   "2026-09-18T14:30:00",
    "tat_lines": [ { "text": "Soupe de courge, graines grillées", "price_cents": 900 } ]
  }
}

A refused shape comes back 400 with a message naming the field, exactly as the editor would have said it.

Over MCP

If you run an MCP server that bridges the WordPress Abilities API — the usual arrangement is an MCP server on the site, or a bridge running beside it — the nineteen appear as tools, with the descriptions above as their tool descriptions. Nothing special is needed on this theme's side: the register is the interface.

We ship no MCP server and recommend none. This is a note about what is possible, not a supported integration.

A two-minute example

"The kitchen has run out of the mushroom tartine. Take it off today's lunch card and put the soup up at nine dollars."

An assistant would do this in four calls:

  1. list-dayparts → the lunch service's slug is midi, it runs Tue–Fri 11:30–14:30, and it is what is being served right now.
  2. list-menu-items with daypart: "midi" → the mushroom tartine's id, and the soup row whose description is empty.
  3. post-slip — kind replaces, clipped to midi, replacing the tartine's id, window from now until the service ends, one line saying what is on instead.
  4. post-slip again — kind special, clipped to midi, one line Soupe de courge, graines grillées with price_cents: 900.

The card now strikes the tartine row, stamps it, hides its photograph, and prints the soup line. At 14:30 both sheets come down by themselves and nothing has to be remembered.

If the assistant had got the service wrong — clipped the Instead slip to breakfast, say — call 3 would have come back refused, naming the dish, the service it was clipped to, and the services the dish is actually served at. That is the point of the five checks: an agent is exactly the kind of caller that gets a target slightly wrong.