Every release post we have written since launch has carried the same sentence somewhere in it: the catalog did not move, still 153 abilities, nothing added, removed, renamed, or repermissioned. That sentence held through 1.6.2, 1.7.0, 1.7.1, 1.7.2 and 1.7.3. In 1.7.4 it stops being true. The catalog goes from 153 to 179: 85 core abilities, up from 83, and 94 across the integrations, up from 70.
Twenty six new abilities, and every one of them arrives off. Nothing in this release turns itself on when you update, and nothing an agent could not already reach on your site becomes reachable because you took the update. That part of the model has not changed and is not going to. If you want the reasoning, off by default covers it.
Five integrations that were not there before
Each one registers only when its host plugin is present, and then still sits behind the enable switch like everything else in the catalog.
The Events Calendar brings 13. Events, venues, and organizers: list them, read one, create, and update. Deleting an event trashes it rather than removing it permanently. These are built on the calendar’s own ORM rather than its REST API, so an agent creating an event goes through the same data layer the calendar itself uses. It needs The Events Calendar 6.17.3.1 or newer. Below that the abilities do not register at all, because the ORM they depend on is not there to build on.
Event Tickets brings 3, all of them reads. Read the tickets attached to an event, read one ticket, read the attendee list. There is no purchase write and no issuance write in this release. Ticket commerce runs through provider-specific flows we could not verify against a real write path, and shipping a write we had not watched work was not something we were willing to do to somebody’s ticket sales. It needs Event Tickets 5.29.3.1 or newer, with The Events Calendar alongside it. Attendee data is real personal data, so it sits behind the same notice the other sensitive integrations do.
Slim SEO brings 2. Read and write a post’s Slim SEO fields, following the same shape as the existing Yoast, Rank Math, and All in One SEO integrations. If you have read handing your SEO metadata to an agent, this is that, for a fourth SEO plugin.
Avada brings 2. One reads the raw Fusion Builder markup on a page, unrendered. The other does a literal text replace and refuses if the replacement would touch the Fusion shortcode tree. Avada is the only page builder in this release that gets abilities of its own, and even here the plugin is not editing a layout. It is reading markup and swapping text that is safely outside the structure.
GeoDirectory brings 4. Read listings, read one listing, create, and update. This one carries an extra step: it stays off even when GeoDirectory is active on the site, until you switch the integration on yourself. Directory listings are business records that people other than you put there.
Two new core abilities
Replace sitewide does a literal find and replace across posts of one type and status. It runs as a dry run by default: it tells you how many matches there are and which posts would change, and writes nothing. Passing dry_run:false is what applies it. Each candidate goes through the same structure check as replace in post, so a match that lands inside markup is skipped and reported rather than applied, and a post owned by a page builder is skipped and counted separately. It is bounded to 50 posts per call, and a larger match set comes back flagged as truncated with the real total. There is no continuation parameter yet, so a job bigger than 50 posts is not one call away from finishing.
Upload media from URL fetches an image over HTTPS and puts it in the media library. The interesting part of it is what it refuses. HTTPS only. Bare IP addresses as hosts are rejected. Private, loopback, and link local addresses are rejected, and the hostname is resolved once and pinned to the connection so the address cannot change underneath the request. Redirects are not followed. The response is size capped and the bytes are sniffed against the same image allow list the regular upload uses, so a file that claims to be a PNG and is not does not get in. An ability that fetches a URL on your server’s behalf is a request forgery risk by construction, and most of the code in this one is there to keep it from being one.
A write that used to do nothing now refuses
Five abilities that write content, update post, update page, update content item, replace in post, and restore revision, now refuse when the target page belongs to Elementor, Divi, Beaver Builder, or Avada. Before this, that write reported success and changed nothing you could see on the front end.
That one is its own story, and it is the more interesting half of this release: a write that changed nothing now refuses. Read that one for what the guard covers, what it deliberately does not, and why it is not page builder support.
An allowlist that only narrows
There is a new per-role and per-connection allowlist sitting alongside the global list of enabled abilities. It can only take things away. A role or a connection can be restricted to a subset of what is already enabled sitewide, and no row anywhere in it can grant an ability the global list has not already turned on. The result is an intersection, never a last-write-wins.
It is enforced twice: once at tool discovery, so a restricted connection does not even see the abilities it cannot call, and again at call time, so seeing a tool in an older cached list does not help anything. A site that never opens the new screen behaves exactly as it did before.
Two limits worth being plain about. The scoping is at role level and at OAuth client level. There is no per-Application-Password scoping, so two Application Passwords held by the same user get the same reach. And the allowlist narrows a set that you have already chosen; it is a second fence, not the first one. The first one is still what you enabled.
Fixes
The bump to mcp-adapter 0.6.1 closed a real multisite bug. On a network site, a session that had genuinely been written could be reported back as a failure, because a guard was reading the old unsuffixed session key while the adapter had moved to a per-site one. A working connection reading as broken is the kind of bug that costs somebody an afternoon.
Several OAuth paths treated a failed database read as permission granted. A deactivated client, a missing client record, and an unreadable registration limit all took the same route: the read did not come back, and the code carried on as though the answer had been yes. They refuse now. A question you could not answer is not a yes, and that is worth stating as a rule rather than as three separate fixes.
Grants belonging to a deleted user are cleared out instead of lingering after the account is gone. The Connections screen shows each identity’s current live role rather than whatever it was when the connection was made, which matters because demoting somebody in WordPress should be visible in the place you go to check who has access.
Two reads that got easier to use
Media search now matches on filename and alt text as well as the title. Before, it only searched titles, which meant a file you had uploaded as hero-banner-final-2.jpg and never retitled was effectively unsearchable.
Get post and get page gained an include_content input, on by default, and a content_length output field that is always present. Asking for a post with include_content:false returns everything except the body, and still tells you how big the body is. That gives an agent a way to look at a 40,000 character page and decide whether it wants it before pulling the whole thing through a context window.
Full history is on the changelog, the current controls are on security, and every one of the 179 abilities, with its permission and its read or write class, is on abilities.