Clearon WordPress MCP
# Clearon WordPress MCP
Local MCP server for controlled Clearon WordPress publishing through the WordPress REST API.
## Safety model
- Read tools may run directly.
- Run `upsert_post_from_payload` in `dry_run` mode before every write.
- Dry runs surface pending source-integrity review items from `payload.source_audit` and warn when the live source-audit report is missing, mismatched, or still blocked; real writes require `source_audit`, re-hash the payload content, and re-check the live source-audit report before writing.
- Contradictory source-audit states are rejected. A payload or live report cannot be both `ready_for_publish_or_update: true` and still blocked by pending findings or `publish_update_gate.blocked`. Approved reports may still retain `publish_update_review_required_findings` as historical evidence.
- Only an exact slug, a valid `wordpress_post_id`, or an `explicit_target_id` can authorize an update, and stored or explicit IDs are rejected when exact-slug evidence points to a different post. Title and near-slug matches produce a conflict for human review.
- Publishing and scheduling require a featured image. Local media is uploaded and attached before the final public post update.
- New posts are created as drafts and promoted only after prerequisites succeed. Existing live posts are not modified until the final combined update.
- `publish_now` refuses already-published targets so it cannot silently reset publication dates on a live post.
- After the final write, the server re-fetches the post and verifies its slug, canonical link, status, featured image, share block, supplied publication date, and featured-image social metadata.
- On a later failure, newly created drafts are trashed, newly uploaded media is deleted, and a modified existing post is restored from its pre-write snapshot when verification proves the result is wrong.
- Payload and image paths must resolve inside the configured workspace root. Set `CLEARON_WP_MCP_WORKSPACE` when the process is not already started from that workspace; symlinks cannot escape the resolved root.
- Image uploads accept JPG, PNG, WebP, and GIF files up to 20 MB and verify the file signature.
- Writes are serialized within one MCP process by the payload slug plus any supplied post IDs so slug-based and ID-based writes against the same post do not race. This does not coordinate multiple independently running server processes.
- Duplicate cleanup verifies numeric WordPress slug suffixes. Permanent deletion requires `confirm_permanent_delete: true`.
## Tools
Read-only:
- `get_server_health`
- `get_auth_mode`
- `get_endpoint_config`
- `get_post`
- `find_posts`
- `audit_slug_state`
Writes:
- `upsert_post_from_payload`
- `upload_media`
- `publish_now`
- `resolve_duplicate_posts`
`publish_now` is no longer a bare post-ID publish shortcut. It requires both `post_id` and `payload_path`, re-runs reviewed payload targeting, proves that the existing target already matches the reviewed payload content, re-checks the live source-audit gate, then publishes with the same verification and rollback path used by `upsert_post_from_payload`. When `publish_at_local` is omitted, the server stamps the current local time in WordPress `YYYY-MM-DDTHH:mm:ss` format.
The legacy direct mutation tools `set_featured_image`, `upsert_share_block`, and `set_social_meta` remain present only as disabled compatibility stubs. They return an error directing callers back to the reviewed payload workflow.
`resolve_duplicate_posts` supports:
- `trash`: move a duplicate to WordPress trash; recoverable
- `draft`: retain it as a draft
- `private`: retain it privately
- `delete`: permanently delete it; requires `confirm_permanent_delete: true`
## Payload requirements
Payloads require non-empty `title`, `slug`, and `content`. Slugs must use lowercase letters, numbers, and hyphens. `categories` and `tags`, when supplied, must contain positive integer IDs.
Payload dry runs may proceed while `source_audit.pending_publish_update_review_findings` is non-empty, but non-dry-run writes require `source_audit` with a revision fingerprint that exactly matches the approved editorial revision when `editorial_approval.sha256` is present, otherwise the current payload content fingerprint. They are blocked unless the latest live source-audit report for that slug also matches that same fingerprint, matches the payload title, is `ready_for_human_approval`, and is `ready_for_publish_or_update`.
Schedule mode requires a valid future `date`. Publish and schedule modes require one of:
- `featured_media`
- `local_featured_image`
- an existing featured image on the exact update target
## Run and test
```bash
cd tools/clearon-wordpress-mcp
npm run syntax
npm test
node server.mjs
```
Safe live smoke test:
```bash
CLEARON_WP_MCP_WORKSPACE=/absolute/path/to/workspace \
npm run smoke -- /absolute/path/to/workspace/path/to/payload.json
```
The smoke test initializes the MCP, checks health, and performs only a payload dry run.
## Recommended workflow
1. Call `get_server_health` and confirm `auth_mode` is not `missing`.
2. Call `upsert_post_from_payload` with `mode: "dry_run"`. If the payload is still marked `draft` but you want dry-run checks for an eventual publish or schedule operation, pass `intended_mode`.
3. Resolve every conflict or warning, including any listed pending source-integrity approvals. Use `explicit_target_id` only after checking the candidate manually.
4. Publish as a draft first for editorial review when practical.
5. Use `publish`, `draft`, or `schedule` only when the dry run identifies the intended target and image and the live source-audit gate is clear.
6. Use `publish_now` only for an already prepared exact target post and pass the same reviewed payload path used for the dry run.
7. Review the returned `verification` result, then call `audit_slug_state` as an independent live-state check.
## Authentication
The server checks:
1. `WP_AUTH`
2. `WP_USER` plus `WP_APP_PASSWORD`
3. `clearonWordPress.wpAuth` in `OPENCLAW_LOCAL_SECRETS` or `~/.openclaw/secrets/local.json`
Credentials are sent only in the WordPress REST authorization header and are not returned by MCP tools or written to logs.
## Failure and recovery
- A failed local image validation performs no WordPress write.
- A failed upload performs no post write.
- Cleanup after a failed later step is best-effort: newly uploaded media is deleted, new drafts are trashed, and verified mismatches on existing posts trigger rollback plus a rollback verification read.
- If WordPress accepts the final write but all three verification reads fail, the server does not guess or roll back an unknown state. It reports that a manual `audit_slug_state` is required before retrying.
- If the final write response is lost or times out, the server treats WordPress state as unknown, skips cleanup assumptions, and requires `audit_slug_state` before retrying.
- JSON logs go to `stderr`. Set `CLEARON_WP_MCP_LOG_LEVEL=info` or `debug` for troubleshooting.
The server does not modify payload JSON files. WordPress state remains the source of truth and should be verified through `audit_slug_state` or your own live-state audit path.
TDQS
Scored across 13 tools
Most tools map to distinct actions, but get_server_health overlaps with get_auth_mode and get_endpoint_config, and get_post/find_posts have similar retrieval purposes. The three disabled tools set_social_meta, set_featured_image, and upsert_share_block share nearly identical 'use a reviewed payload workflow' descriptions, which adds ambiguity.
The set mostly follows a verb_noun snake_case pattern like get_post, upload_media, audit_slug_state, and resolve_duplicate_posts. Minor deviations such as publish_now and the mix of set_/upsert_ for disabled mutation tools keep it from being fully consistent.
13 tools is a reasonable size for a WordPress publishing server. However, three of those tools are disabled stubs that add clutter rather than functionality, so the effective tool surface is closer to 10.
The active tools cover post retrieval, payload-based upsert/publish, media upload, and duplicate management. Notable gaps remain: no direct way to set featured images or social meta, no general media retrieval, and no delete/update flow outside the payload workflow.