← Ppok AI Toolkit

Release log

A running record of what's shipped in the Ppok AI Toolkit — newest first. The plugin is in active development; versions land in rapid succession as new abilities and safety layers come online.

v1.0.1 current

Completing the OAuth happy path

Three improvements surfaced from running v1.0.0 against a real Claude Desktop client. Each one was needed for the OAuth flow described in v1.0.0 to actually complete end to end on a typical WordPress install — they ship together as v1.0.1 so the entire happy path becomes reachable in a single upgrade.

  • Robust gate priority on the REST filter chain. The Resource_Server hook now runs at priority 11 (was 9), so its 401 + WWW-Authenticate response is the last word in the chain even when another plugin (ACF Pro, for example) registers a void-returning rest_pre_dispatch callback at priority 10. On installs where that pattern existed, MCP clients previously couldn't reach the OAuth discovery anchor; they now do.
  • OAuth discovery at the standard well-known URLs. /.well-known/oauth-authorization-server (RFC 8414 §3) and /.well-known/oauth-protected-resource (RFC 9728) are now served at the site root, which is where spec-compliant clients construct the URL and look. The previous /wp-json/… paths remain live as back-compat aliases — both serve identical content. Claude Desktop's mcp-remote bridge can now complete autonomous OAuth bootstrap.
  • Sign in once and continue to consent. After logging in at wp-login.php to authorize an MCP client, the consent screen now actually renders. WordPress's default REST cookie-auth gating expects an X-WP-Nonce header that server-driven redirects from wp-login don't carry — the authorize endpoint now re-derives the current user from the auth cookie directly so the post-login redirect lands on the consent screen instead of looping back to login.
  • Tighter release build. Build script now refuses to ship a per-machine .claude/ directory and adds zip-size guards (warn at 500 KB, hard-fail at 2 MB) so a future bypassed --no-dev install can't quietly produce a fat-vendor zip.

Download v1.0.1 .zip

v1.0.0 milestone

Remote MCP over OAuth — no bridge required

The v1.0 milestone. Paste https://your-site.com/wp-json/mcp/mcp-adapter-default-server straight into Claude.ai's "Add custom integration" UI and connect — no Node bridge, no command-line setup, no companion services. The plugin is now both the OAuth Authorization Server and the Resource Server, so a fresh WordPress install can stand up a remote-MCP endpoint by itself.

  • OAuth 2.1 + PKCE (S256). Open Dynamic Client Registration (RFC 7591) means Claude.ai and other MCP clients can register and connect without any pre-shared secret. HTTPS is hard-required, with a localhost loopback exception for dev and a filter for reverse-proxy TLS-termination setups.
  • Per-ability scopes. Every registered ability maps 1:1 to its own OAuth scope (mcp.ping, mcp.rest-call, mcp.set-post-blocks, …). The consent screen groups them as Read / Write — reads pre-checked, writes require an explicit tick — matching the same asymmetric posture the plugin has used since v0.2.
  • Opaque tokens, hashed at rest. SHA-256 in the database; plaintext returned to the client exactly once. Default TTLs: 1h access, 30d refresh (both filterable). Refresh-token rotation with family-wide reuse detection — a replayed refresh token revokes the entire token family.
  • RFC 8414 + 9728 discovery. .well-known/oauth-authorization-server and .well-known/oauth-protected-resource are live, and the Resource Server's 401 emits a WWW-Authenticate: Bearer resource_metadata="…" header so MCP clients complete discovery autonomously.
  • OAuth-only on MCP routes. The rest of the WordPress REST surface is untouched — Application Passwords, cookies, and existing integrations keep working exactly as before. Only the /mcp/* namespace requires a Bearer token.
  • Revocation + housekeeping. RFC 7009 /oauth/revoke endpoint. A daily WP-Cron tick prunes expired authorization codes and revoked tokens past a configurable grace window (default 30 days).
  • OAuth event audit log. A dedicated ppok_ai_oauth_events table records every client_registered, consent_granted, token_issued, token_refreshed, token_revoked, and reuse_detected event — separate from the existing ability-invocation log so each has its own lifecycle and retention story. Each MCP-attributed ability event now also carries the actor_token_id that authenticated the call.

Download v1.0.0 .zip

v0.4.6

Block templates by example

A new read-only ability that infers a block's schema empirically — by sampling how the block is actually used on the site — plus a framework-adapter seam so plugin-specific data shapes (ACF, Gutenbricks, future others) can layer richer metadata on top. Closes the cold-start gap where an AI knows a block exists (from v0.4.0's blocks-registered) but doesn't know what to put in it.

  • ppok/block-template — samples up to 20 existing instances of a block and returns keys_observed (with type, present-rate, redacted sample values), required_keys, paired_keys (with role hints like value/label and src/alt), and variant_signals. Two-level flatten on associative attrs so nested shapes like ACF's data.<field> surface cleanly.
  • Works on opaque blocks. Gutenbricks-style attrs with names like gb-vdxvia / gb-pqmvuv still get useful pairings via URL-shape detection and a length-differential heuristic — the shorter, repeated value gets tagged as the label, the longer one as the value. No registered schema required.
  • Framework adapter seam. A new ppok_ai_toolkit_framework_adapters filter lets third parties register a Framework_Adapter instance that overlays plugin-native metadata onto the empirical baseline. Two built-ins ship: ACF (projects field-group fields whose location rules target the block) and a Gutenbricks placeholder (documents the future enrichment point until Gutenbricks exposes a stable introspection API).
  • Honest output. Redacted sample values (80-char truncation), <list[N]> / <map[N]> elision for complex values, mixed type fallback when no single type dominates, and an adapters_consulted list so callers can tell which overlays contributed.

Download v0.4.6 .zip

v0.4.5

Auto-updates, end to end

The piece that closes the loop on the self-hosted update channel started in v0.4.3 and v0.4.4. The plugin now registers a handler on the hostname-scoped update_plugins_ppok-ai.com filter, fetches update.json, and reports new versions to WordPress directly — so the standard "Update Available" prompt fires on every site that runs v0.4.5 or later.

  • Native WordPress update flow. No third-party update library. WP's built-in cron job (wp_version_check) hits the new handler, which translates the hosted JSON into the stdClass shape WP stores in its update_plugins site transient.
  • Cached the right amount. Update payloads are cached for 1 hour in a site transient (1-minute negative cache on fetch failure); the existing "View details" channel from v0.4.4 stays at 6 hours. Shared fetch() helper, separate cadences.
  • Forgiving JSON contract. The translator accepts either version or new_version, plus aliases homepage/url and download_url/package, so the hosting side can evolve without breaking consumers.

Download v0.4.5 .zip

v0.4.4

Page outline + "View details" channel

A new read-only ability for cheap structural scans, and the companion to v0.4.3's Update URI header that wires up the wp-admin "View details" modal — so plugin info comes from the same source that drives auto-updates.

  • ppok/page-outline — depth-tracked flat outline of a post's block tree, returned as [{block_name, depth, brief_data_summary, anchor?}]. No rendered HTML, no full attrs, no innerContent — typically under 2KB even on pages where get-post-blocks returns 100KB+. Outline is the index; get-post-blocks is the content.
  • Custom-block friendly summaries. brief_data_summary falls back from stripped innerHTML to text-shaped attrs (content, text, title, alt, caption, label) so blocks from Gutenbricks, ACF Blocks, Spectra, and friends still summarize cleanly. Empty-freeform parser artifacts (whitespace blocks between adjacent delimiters) are filtered out — the outline reflects structure, not noise.
  • "View details" modal now works. A new info channel hooks plugins_api, fetches info.json, and populates the WordPress plugin-information modal. Cached in a site transient for 6 hours (1-minute negative cache on failure), URL overridable via the ppok_ai_toolkit_info_json_url filter.

Download v0.4.4 .zip

v0.4.3

Dry-run authoring

Three abilities gain dry-run affordances so agents can verify their markup, scope, and routing decisions before committing anything to the database. Closes the loop that previously forced agents to ship to real drafts just to confirm a block tree round-trips cleanly.

  • ppok/set-post-blocksvalidate_only flag. Runs the full gate stack and a serialize_blocks / parse_blocks round-trip, then returns {bytes_written_would_be, unknown_blocks, schema_violations, roundtrip_drift_blocks} without touching wp_update_post. Diagnostics are collected (the call never halts on a single failure in dry-run), and drift is computed structurally on the block tree, not on innerHTML whitespace.
  • ppok/replace-in-content — honest preview. dry_run (already default true) now predicts apply-path verdicts per candidate with a would_skip field (permission_denied or scope_blocked). The preview now matches what would actually happen on apply.
  • ppok/rest-call — opt-in validate_only. On POST/PUT/PATCH, short-circuits with a structured validate_only_not_supported error by default (since no WP core endpoint honors the flag). New ppok_ai_toolkit_validate_only_routes filter lets admins allowlist routes that genuinely support validation-only dispatch; for everything else, the recommendation is to POST with status: "draft" as the safest dry-run.
  • Native WordPress auto-updates. Plugin now declares Update URI: https://ppok-ai.com/plugins/ai-toolkit/update.json, so WP 5.8+ checks for new versions directly — no third-party update library.

Download v0.4.3 .zip

v0.4.2

Release packaging tooling

Adds a composer build script that produces a clean, distributable plugin zip — slim production dependencies, version-stamp parity checks across the plugin header, version constant, and readme.txt stable tag, and per-version archives so each release stays addressable.

  • One-command builds. composer build stages a clean copy, runs composer install --no-dev --optimize-autoloader, and writes ppok-ai-toolkit-{version}.zip to a configurable target directory.
  • Version parity, enforced. The build aborts if the plugin header Version:, the PPOK_AI_TOOLKIT_VERSION constant, and readme.txt Stable tag: ever drift.
  • Won't clobber a shipped version. Refuses to overwrite an existing zip, so the target directory doubles as a per-version archive.

Download v0.4.2 .zip

v0.4.1

Agent-DX patch

A ten-item polish pass that smooths over rough edges agents hit in the field. Together these changes cut token waste, sharpen response shapes, and make error payloads self-explanatory enough for an AI to handle them without human help.

  • Structured permission errors. ppok/get-post-blocks now returns a structured error payload carrying the gate name, required capability, and target post id — so the agent can adapt its next call instead of asking the user what went wrong.
  • 87KB → 10KB block catalog. Optional include_schema toggle on ppok/blocks-registered lets agents enumerate the block roster without dragging the full attribute schemas along.
  • Rendered-HTML stripping by default. ppok/rest-call drops content.rendered, title.rendered, excerpt.rendered, and guid.rendered on write responses; opt in with include_extended=true.
  • Caller-specified slimming. New slim_response_keys on ppok/rest-call lets the caller drop arbitrary top-level keys per row.
  • Deterministic ordering. ppok/list-posts gained orderby + order (whitelisted), defaulted to modified DESC, with a stable secondary sort by ID DESC.
  • Friendlier schemas. ppok/rest-call accepts route as a synonym for path; ppok/blocks-registered exposes a grouped namespaces summary.

Download v0.4.1 .zip

v0.4.0

Block intelligence

Three new read-only abilities close the "agent guesses what exists" loop. Instead of scanning posts to discover what blocks and patterns live on the site, an assistant can now enumerate the registries directly.

  • ppok/blocks-registered — dumps every registered block type (core, theme, plugin, custom) with name, title, description, category, dynamic flag, and attribute schema. Optional namespace-prefix filter.
  • ppok/blocks-find-usage — takes a canonical block name and returns the posts that contain it with per-post counts. SQL LIKE prefilter plus a real parse_blocks + recursive innerBlocks walk, so a marker string inside another block's HTML never false-positives.
  • ppok/patterns-registered — exposes the block patterns registry (core, theme, plugin) that the REST API otherwise leaves unreachable. Optional category filter; include_content=false for cheap catalog enumeration.

Download v0.4.0 .zip

v0.3.0

Preview URLs for visual review

A new ppok/preview-url ability mints a short-lived (5-minute), HMAC-signed URL that bypasses the draft/pending/private redirect — closing the design-feedback loop. The AI proposes a change, hands the user a one-click link, and the user sees the draft rendered through the full theme without logging into wp-admin.

  • Signed and expiring. Tokens are hash_hmac sha256 over post id + expiry, keyed with wp_salt('auth'). Invalid or expired tokens are a no-op — WordPress serves its normal 404.
  • Admin opt-in + audit logged. Even though no database mutation occurs, minting a bypass credential is a side effect — so the ability is gated by abilities_enabled and every mint is recorded in the activity log.
v0.2.1

Live deploy verification

First end-to-end verification against a real WordPress install. The transport-stability layer from v0.2.0 held up under real traffic, and the run surfaced two opportunities to expand input handling.

  • Wider input shapes. replace-in-content now accepts the natural single-string forms for post_type and post_status (in addition to arrays), so callers don't have to wrap a single value in a list.
  • Attribute-aware find/replace. Many modern block plugins (Gutenbricks, ACF Blocks, Spectra) store text inside block.attrs rather than innerContent. New opt-in attrs_text_keys parameter recurses into attributes and applies find/replace at matching keys; default off preserves original semantics.
  • Real-world transport behavior. A 15.8 MB REST response (yes, really) returns a structured response_too_large payload with byte counts and correlation id — the agent can now branch on it cleanly instead of treating it as a connection error.
v0.2.0

Writes, scope gates, and transport defenses

The first ability set that mutates content — behind five layers of safety. Introduces a block-aware write path, bulk find/replace, and the L3 / L4 gates that turn "AI can do anything I can do" into something you'd actually trust on a production site.

  • ppok/set-post-blocks — accepts a parsed block tree, runs the full gate stack (block allowlist, scope, capability), captures a pre-update revision, and writes via serialize_blocks.
  • ppok/replace-in-content — block-aware bulk find/replace; dry_run defaults true and returns matched posts, total replacements, and preview snippets with context labels before any write lands.
  • Scope gates (L4). Writes are limited to specific post types and statuses (default: draft posts only). Promotion to publish additionally requires edit_published_posts.
  • Block allowlist (L3). Registered-only or curated mode; the walker recurses through innerBlocks so nested unknown blocks can't slip past.
  • Transport defenses on rest-call. 1MB response cap, structured response_too_large errors, a try/catch that converts any throwable into a clean WP_Error, and a correlation id stamped onto every response.
  • Audit log gets richer. Errors are classified into typed result codes (response_too_large, unknown_block, scope_blocked, …) so the activity viewer's category filter actually means something. Oversize payloads are stubbed at 256KB instead of bloating the events table.
Phase 3

Discovery aggregator + DX optimization

A token-efficiency pass on read responses, plus a new aggregated discovery ability so an AI can learn the whole surface in one round trip instead of N+1 calls.

  • ppok/abilities — bundled discovery returning {name, title, description, input_schema, output_schema, example} per ability in a single call. Collapses discover-abilities + N × get-ability-info to one round trip.
  • Noisy fields stripped by default. yoast_head, yoast_head_json, permalink_template, class_list, generated_slug, and _links are dropped from rest-call responses; include_extended=true keeps them.
  • Cursor pagination. GET collection responses with more pages get has_more=true and a next_cursor that the agent passes straight back in without manually managing page params.
Phase 2

Admin surface

A real settings page and a real activity viewer — the two surfaces a site owner needs to actually trust an AI on their site.

  • Settings page on the WordPress Settings API. Toggle individual abilities on, choose retention, configure scope gates (write post types & statuses), and pick block allowlist mode.
  • Activity viewer at Tools → Ppok Activity. Filter by ability, result, error code, MCP client, actor, target post, correlation id, or date range. Row-detail screen pretty-prints payloads and renders diffs when present.
Phase 1

Audit foundations

Every audit row now carries the metadata you need to investigate later — correlation id, MCP client, originating IP — populated from a single shared request context.

  • Correlation ids on every call. Sourced from X-Request-ID or X-MCP-Session when present, UUID fallback otherwise.
  • MCP client + IP captured alongside the actor on every event.
Initial

The first ability: ppok/rest-call

A generic WordPress REST pass-through wrapping rest_do_request() — one ability that exposes the entire REST surface your role can hit, gated by the same capability checks that already protect your site. No bespoke API for the AI to learn; if you can do it in wp-admin, the AI can do it through MCP.

Sign up to stay in the loop!