Repository navigation
WordPress Core Abilities #40
Description
Activity
For:
Posts and Pages
- core/find-posts
- core/get-post
- core/create-post
- core/update-post
- core/find-pages
- core/get-page
- core/create-page
- core/update-page
I would combine them to do CRUD operations on any public CPT. This will reduce the number of tools by only adding one extra input,
post_type.
Something similar to: https://github.com/galatanovidiu/mcp-adapter-implementation-example/blob/main/src/Abilities/Posts/ListPosts.php#L28Reacted by Dovid Levine, Pascal Birchler and Greg ZiółkowskiOpen Questions
- Plugin Management: This proposal includes abilities to activate, deactivate, and update plugins. Given the potential for site instability, what guardrails are essential?
Imo this q is solved by recognizing that these are destructive actions, and considering them beyond the scope for now:
core/update-plugincauses irreversible changes to files and potentially database structures, would need a mechanism to "roll back" the update (files + db) to the specific pre-update version.core/deactivate-plugin:- can often cause database changes as well (
Delete settings on deactivateis a common option), though that could be worked around by requiring plugins who useregister_deactivation_hook()to allowlist in, via a (theorycraft) ability_supports( 'core/deactivate-plugin', 'my-plugin-name ), - However, the ability to "break" frontend site functionality is easily worse with
Theme switchingandmodifying menus.
- can often cause database changes as well (
core/activate-plugin: The least "destructive" of all three, but- IMO still on par with
Theme switchingandmodifying menus(though not as easy to reverse than e.g. a FSE theme switch or a menu revision). - Without
core/deactivate-pluginit's not reversable at all.
- IMO still on par with
- Destructive Actions: This initial set deliberately excludes destructive actions like deleting posts or users. Should a future version include them?
This seems like a great candidate for exploration and iteration in AI Experiments
All ability names below follow the established namespace/ability-name convention enforced by the API. The core namespace is used to designate that they are part of the WordPress Core set.
Surfacing since there's no GH issue/discussion to tag: @galatanovidiu brought up the idea (Slack) of having a "clear definition" of what namespaces should represent, and the possibility of groupings via nested namespaces.
I appreciate the in-depth discussion on this topic. I'd like to contribute a few points to the conversation:
- Abilities as "One More Way": I envision the abilities API as "one more way" for users to achieve results, as an alternative to the WordPress admin UI. Of course, we must ensure users are fully aware of what's happening and confirm potentially destructive actions. For this, the Model Context Protocol (MCP) standard includes a feature called "elicitation," which allows the MCP server to request additional information from the user (such as confirmation) before executing a task. More information here.
- Handling Destructive Operations: For the reason above, I would not limit plugin management or other destructive operations, as long as we can guarantee that the user is forced to confirm before proceeding. We should simply ensure that LLMs do not perform such actions without explicit confirmation. I believe over-engineering with the possibility of "undo" actions is out of scope. Currently, when using the standard WordPress UI, the user cannot easily undo these destructive operations.
- Unified CRUD Interface: I agree with the proposal of having a unified CRUD interface for all post types with a
post_typeparameter. This approach is consistent with existing WordPress functions like wp_insert_post, wp_update_post, etc, which promotes a familiar and standardized development experience.
Reacted by John Parris and Jason AdamsFor this, the Model Context Protocol (MCP) standard includes a feature called "elicitation," which allows the MCP server to request additional information from the user (such as confirmation) before executing a task. More information here.
@marcochiesi, some great feedback here. It deserves its own issue, as this topic is more nuanced. In particular, MCP is a great example where some additional hints help to distinguish the type of operation. I can think of more use cases, like including information whether something is read-only, what's a safe action, what's a destructive action, and what's a resource (an image or other media). It's going to be useful with MCP, but also with the existing Command Palette in WP Admin to provide some unified workflows. Would you like to expand on this topic with your thoughts in a newly created issue?
Reacted by Dovid Levine@marcochiesi, some great feedback here. It deserves its own issue [...]
It makes sense, however, I am not totally sure if this should be territory for the Abilities API or for the MCP Adapter project (or maybe both), so I am unsure about where to post such issue. A possible approach could be:
- The Abilities API should be responsible for providing the necessary information including metadata or "hints" that describe the nature of each action (e.g., read-only, safe, destructive). This makes the API a reliable and declarative source of truth about what each ability does.
- The MCP adapter (or any client consuming the API) should be responsible for the logic. It would read the hints provided by the API and, based on that information, decide how to handle the action. For a destructive action, the adapter would trigger a user confirmation prompt (elicitation) before proceeding.
WDYT?
@marcochiesi the current separation of concerns has the Abilities API (this repo) responsible for allowing functionality to be called decoupled from traditional WordPress flows. The goal is to be able to register abilities once, and not need to tech-debt/reinvent every time a new way of interacting with WordPress sites (via AI, but tbh in any decoupled context) is hyped.
The MCP Adapter provides a MCP-compatibile API shape for the exposed WordPress functionality. The only logic there should be what's needed to interact with the ability.
If/when other standards (e.g. A2A) gain traction, those "last-mile" Adapters will all be able to reuse abilities, independently of adoption/adaptation of MCP.
It's even possible that in the mid-to-long term future even REST/GraphQL endpoints can be API wrappers for the same abilities, but that's obviously long ways before even being a discussion.
@Jameswlepage Back to your original statement about the work that the initial build is going to achieve. From reading the list, I can't help but see some similarities between the WP CLI and the REST API. As people stated above, this is "just another way" to interact with WordPress. As such, the naming conventions, namespaces, aliases, class/function names, and features should closely align with those existing APIs. This is more of a philosophical comment, and I hope you can lean on the other teams and APIs to flesh out your feature set and naming conventions.
Reacted by Pascal Birchler, Seth Rubenstein and Ovidiu GalatanReacted by Dovid Levine@swissspidy, do you have some recommendations on how to shape the general-purpose abilities based on your experience with both WP CLI and trying to map REST API endpoints to tools from your MCP for WordPress work? The following issue comes to my mind:
Sure. Let me try to address some of the points raised in this discussion so far in general:
First, I agree with @marcochiesi regarding destructive actions. It's not the Abilities API's or the MCP adapter's job to limit destructive options or implement additional safeguards like rollbacks or opt-in. We already have permission checks, allowlists, and and concepts such as elicitations in MCP. And if you interact with abilities through the Command Palette, deactivating a plugin is not different from clicking the link on a plugin page. Thus, we should not deliberately exclude anything in this regard. This is out of scope.
The Abilities API should definitely have a way to provide as much metadata as possible (e.g. read-only, destructive, idempotent, requires confirmation, etc.)
Second, @galatanovidiu is right that we need to combine CRUD operations as much as possible. Separate tools per post type or so do not make sense. When it comes to MCP, providers usually have hard limits on the number of tools. Last I checked, 128 for OpenAI, 512 for Google. So there we need to keep that in mind.
For such CRUD operations, WP-CLI is definitely a good example.
wp postworks for any post type, just pass the--post_typeargument. The REST API is different, every post type has its own route. Both have pros and cons. Also worth noting that WP-CLI covers way more than the REST API as well (e.g. there is a command to install translations, but no REST route for that).When I think about using abilities via a command palette to create new content and I type "Create a new ...", as a user I would love to see different options "Create a new page", "Create a new product", and so on. However, for an MCP use case, I only want one
create_posttool that takes apost_typeargument. Is this something we could reflect in the API design somehow?I think that would cover both scenarios: a granular list of abilities for users, and a more condensed list for machines. Hope that makes sense :-)
Reacted by Felix Arntz, Jason Adams and John ParrisIt's not the Abilities API's or the MCP adapter's job to limit destructive options ... Thus, we should not deliberately exclude anything in this regard.
My understanding of "scope" in this context was regarding the short deadline between now and WP6.9 Beta 1 and our need to prioritize and not ship tech debt into core. It's not about excluding destructive actions entirely but doing them iteratively and additively.
To your actual point:
Unlike Command Palette et al, MCP allows for autonomous execution of destructive action without proving user intent. So IMO there's at least some additional consideration that needs to occur. It might not be something that belongs in
abilities-api, maybe it's not something in MCP Adapter, maybe it's only in the client, or somewhere else altogether. (Whatever "it" is).
When I think about using abilities via a command palette to create new content and I type "Create a new ...", as a user I would love to see different options "Create a new page", "Create a new product", and so on. However, for an MCP use case, I only want one create_post tool that takes a post_type argument. Is this something we could reflect in the API design somehow?
From the way you're describing this, it sounds like this should be an implementation detail to be solved in the CP and MCP implementations eg
- Command Palette would just loop through the input schema -in this example the post_type enum- to translate arguments into semantic commands
- MCP could group them with certain
metaor by simply respecting nested namespaces if we go that route here.
Assumedly, translating abilities to REST endpoints or CLI commands or GraphQL mutations, or whatever other existing or future use case for abilities would similarly reach their ideal shape by inferring from the schema / meta where possible.
Or is there something more explicit/deterministic you have in mind?
@JasonTheAdams opened an issue covering the hints for destructive actions, so we can move some of the related conversation there:
Reacted by Pascal Birchler and Dovid Levine- added[Type] OverviewComprehensive, high level view of an area of focus often with multiple tracking issuesComprehensive, high level view of an area of focus often with multiple tracking issues
on Sep 9, 2025 From the way you're describing this, it sounds like this should be an implementation detail to be solved in the CP and MCP implementations eg
Or is there something more explicit/deterministic you have in mind?Not sure, we'll have to test this. Just looping through abilities reduces control and causes issues with internationalization as well (because you'll have concatenate strings to say "Create a new [post type]", which is not ok)
Reacted by Dovid Levine67 remaining items
@neillmcshea when you're back, mind breaking out this issue into separate ones for each ability (or groups of abilities) so they can be planned and tracked separately versus this gigantic epic issue?
I updated the issue description to reflect the work completed so far.
Before we open additional issues for the remaining abilities, could we confirm whether we’re aligned with the direction proposed by @jorgefilipecosta in the Merge Proposal: Expanding WordPress Core Abilities? Specifically, organizing Core abilities around broader
read/managepairs wherever it makes sense?Establishing and documenting a shared direction would help us structure the remaining work consistently and keep the architectural discussion centralized. If consensus has not yet been reached, where should that discussion and decision take place?
@JasonTheAdams we'll want your review/approval on the comment/request above on overall direction for abilities.
I'd like to raise the argument here that core abilities should not be added in the AI Experiments plugin, but rather a separate canonical/feature plugin, similar to the MCP Adaptor. A few reasons:
- The Abilities API is already in core, and the assumption is that core abilities should follow. Not everything in the AI plugin is meant for core, so a separate plugin would be a more common testing ground for this specific feature.
- Abilities are fundamental primitives- beyond AI generally, and beyond this plugin's scope specifically. Abilities are necessary for the MCP adaptor and potentially other use cases as well (workflows and the command palette) and should be something we can test and iterate on in a distinct environment.
- This plugin comes with an opinionated UI centered around AI tools in the WordPress admin. If a ecosystem developer (such as Elementor, Miles, and many others who are requesting core abilities) wanted to include core abilities as a plugin dependency or bundled package, they'd need to opt into including the entire AI experiments plugin and it's UI. We should give users the option to test the core abilities without these additional features.
- We can tell a clearer story about WordPress MCP if it's possible to start testing it without this experiments plugin enabled and instead just a Core Abilities feature plugin and MCP Adaptor.
I know there are plenty of reasons why they should be developed in here (distribution being one of them), but I think we should at least consider whether a traditional feature plugin approach would be a better long-term home for iterating on these separately. I believe a similar argument was made above by @johnbillion, though maybe for different reasons, but I wanted add additional perspective.
Following the request above to break this epic into per-ability issues, and the 7.2 roadmap's line about expanding read-only coverage to media, taxonomies, and comments, I've opened one issue per resource for the read side:
- Add a
core/media-queryability (read-only Media Library coverage) #1062core/read-media - Add a
core/terms-queryability (taxonomies, categories, tags) #1063core/read-terms(with aread-taxonomiescompanion question) - Add a
core/comments-queryability #1064core/read-comments
Each follows the read/manage shape from the merge proposal and mirrors the matching REST controller's permission checks. The
manage-*counterparts and thecontent-create/update/deletevsmanage-contentnaming question from #1025 are left for separate issues once that direction is settled.- Add a
Thanks, @whyisjake, for creating these issues! I’ve adjusted the machine-readable ability names to align with @jorgefilipecosta’s draft proposal, which also includes the full list of proposed abilities. Jorge, could you share the proposal here once it’s finalized?
As far as I can tell, we already have site settings, users, and content covered in the proposal. Together with the issues Jake opened and the full list in the proposal, we should have enough to break down the remaining work into individual issues for these areas.
What still needs further tinkering is:
- plugins
- themes
- site editing
@bacoords, thank you for raising the topic of abilities distribution before they land in WordPress Core. The conversation continues on WordPress Slack at https://wordpress.slack.com/archives/C08TJ8BPULS/p1790794926977199 (registration at https://make.wordpress.org/chat/).
Following yesterday's sync chat, I wanted to share a more structured update. We are finishing the core features for searching and handling WordPress content, users, and settings. Two design questions have shaped this work. The first is which resources are available through abilities. The second is whether abilities execute through existing REST endpoints or dedicated implementations.
Reusing
show_in_restfor exposureshow_in_restcontrols a resource’s REST API exposure. The proposedshow_in_abilitiesflag provides a separate opt-in for abilities.We considered using
show_in_restdirectly, or as a fallback whenshow_in_abilitieswasn’t specified. This would let existing registrations work with less configuration.Testing showed why that assumption is problematic. In the settings experiment, the fallback expanded the exposed settings from 18 to 66, including connector API keys. Those keys are masked when WordPress prepares the REST response, but the direct ability implementation didn’t run that step and returned their raw values. REST exposure was safe only together with the protections in the REST execution path. Testing details
This exposed a problem with inheriting REST’s exposure flag while bypassing its response protections.
Post types have similar considerations. Developers may enable
show_in_restto support the block editor and rely on a custom REST controller or response filters. That existing choice shouldn’t silently become permission to expose the same resource through another implementation. An explicitshow_in_abilitiesopt-in makes that decision visible, with capability checks still determining what each caller can do. Content review discussionUsing REST endpoints as the execution backend
We also have working REST-backed implementations for reads and content writes. This is an attractive intermediate approach because it reuses mature permission checks, sanitization, query behavior, and write handling, reducing how much logic needs to be recreated. It also inherits future endpoint fixes. Read comparison, write alternative
The tradeoff is inheriting REST-specific behavior too. The write alternative documents differences involving Block Hooks and REST insertion and deletion hooks. Those integrations can be useful when matching REST behavior is the goal, but they also make REST customization part of an ability’s behavior. Documented differences
With a REST-backed implementation, a filter that removes or changes a REST response field can also change the ability’s result. Adding a REST field, however, doesn’t automatically make it available through the ability’s schema and field mapping. Developers could end up changing REST behavior to customize an ability. They could also change an ability unintentionally while customizing REST. Mapping implementation
Explicit exposure and dedicated implementations
My preference for the long term is
show_in_abilitiescombined with implementations built on WordPress’s underlying APIs. This gives abilities an explicit contract that can work across different execution contexts, including REST itself.That still leaves plenty of room for reuse. For example,
show_in_abilities => truein the settings proposal reuses the REST name and schema. An explicit array supplies ability-specific definitions. We can share established definitions without automatically sharing exposure or controller behavior. Settings proposalDedicated implementations require more review and ongoing work to prevent drift. That is why the REST-backed implementation has been valuable as a comparison tool. It lets us carry forward roughly a decade of established REST behavior and decisions, investigate discrepancies, and make departures deliberately. The comparison reported matching results across its test suite, while explicitly stopping short of claiming complete equivalence. Verification purpose and results
We’re applying that approach to writes too. The settings PR ports REST endpoint tests and reports a side-by-side comparison of updates, documenting intentional differences. Settings write validation
I see REST reuse as a useful way to accelerate development and a continuing reference for correctness. For the long-term API, I favor explicit exposure, deliberate reuse of shared logic, and documented, tested behavior that developers can reason about independently of REST customizations.
Reacted by Jeffrey Paul, Nik McLaughlin and Brian Coords
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsIn discussion / Needs decision
- StatusShow more project fieldsIn progress
As the Abilities API is developed for inclusion in WordPress Core, we need to define a default set of abilities that will be bundled with it. This proposal outlines a foundational set of abilities intended to be safe, useful for the majority of use cases, and non-destructive by default.
All ability names below follow the established
namespace/ability-nameconvention enforced by the API. Thecorenamespace is used to designate that they are part of the WordPress Core set.Proposed Core Abilities
Site and Settings
core/get-site-info(WordPress 6.9)core/get-environment-info(WordPress 6.9)core/read-settings(AI Plugin 1.1, Add a core/settings ability #691)core/manage-settings(Addcore/settings-updateability #764)Users
core/get-user-info(WordPress 6.9)core/users-query(AI Plugin 1.2, New Ability: core/read-users #774)core/get-usercore/find-userscore/update-user-infoPosts and Pages
core/content-query(AI Plugin 1.2, Add core/read-content ability #739)core/find-postscore/get-postcore/find-pagescore/get-pagecore/create-postcore/update-postcore/create-pagecore/update-pageMedia
core/find-media-itemscore/get-media-itemcore/upload-media-itemcore/update-media-itemTaxonomy
core/find-categoriescore/get-categorycore/find-tagscore/get-tagComments
core/find-commentscore/get-commentMenus
core/get-menu-locationscore/get-menuThemes
core/get-active-themecore/list-themesPlugins
core/list-pluginscore/get-plugincore/activate-plugincore/deactivate-plugincore/update-pluginOut of Scope for this Proposal
Open Questions
Plugin Management: This proposal includes abilities to activate, deactivate, and update plugins. Given the potential for site instability, what guardrails are essential? Should these actions be limited to an allowlist of specific plugins by default to prevent unintended changes?
Destructive Actions: This initial set deliberately excludes destructive actions like deleting posts or users. Should a future version include them? If so, what additional security measures, like a 'trash' or 'undo' ability, would be required to maintain a high degree of safety?