| 开发者 | deboring |
|---|---|
| 更新时间 | 2026年10月14日 10:57 |
| 捐献地址: | 去捐款 |
| PHP版本: | 8.0 及以上 |
| WordPress版本: | 7.1 |
| 版权: | GPL-2.0+ |
| 版权网址: | 版权信息 |
mcp-adapter-discover-abilities and confirm the webmastery-site-toolkit-for-mcp/* abilities appear.Yes. The unchanged 2.6.0 production ZIP passed isolated local HTTP checks against Adapter 0.6.1 and 0.7.0 on WordPress 7.1.2/PHP 8.2 and WordPress 6.9/PHP 8.1. All 75 native-install abilities were discovered and projected as individual tools. Representative reads, draft writes, permission denials and errors passed, including the 2026-07-28 sessionless protocol. These checks do not cover every callback or optional provider. No live or staging site was used. This historical result is separate from 3.0.0 release-package validation. Assessment: https://github.com/DanielBoring/webmastery-site-toolkit-for-mcp/blob/main/docs/mcp-adapter-0.7-assessment.md
An independent production ZIP from main commit 115b577bf59e4d3c33b0ccc78d9317e09efab3e1 passed focused isolated protocol tests against Adapter 0.6.1 and 0.7.0 on WordPress 7.1.2/PHP 8.2 and WordPress 6.9/genuine PHP 8.0.30. Those tests cover the 85-ability fixture inventory, canonical errors, strict inputs, bounded reads, permissions and bulk destructive safeguards. That historical package carried the 2.6.0 version header. It does not certify the separately versioned 3.0.0 package or every callback; no dependency-baseline promotion is implied. The assessment records release-package validation separately.
Failures now use success:false and an error object with code, reason, message, and object-shaped details. Seven categories replace mixed codes; precise legacy reasons move to reason. MCP Adapter 0.6.1 tool errors carry this JSON in one text block with isError:true; structuredContent is omitted on HTTP (internally null). Error normalization preserves successful payloads and gateway success wrapping; separate metadata projections and additive untrusted_fields markers change success contracts as described below. Bulk summaries are non-atomic; inspect every item even when the batch succeeds. Provider diagnostics are redacted without bypassing capability checks. WordPress 6.9 / PHP 8.0 minimums are unchanged. Metadata/SEO reads now enforce effective object/key authorization; migration never grants capabilities. Migration matrix and examples: https://github.com/DanielBoring/webmastery-site-toolkit-for-mcp/blob/main/docs/3.0-migration.md Permanent media/category/tag deletion and both bulk post operations now require the exact JSON boolean confirm:true, including bulk previews. Bulk requests accept at most 100 raw IDs and process duplicates once; dry_run:true reports would-act successes without mutation. These explicitly documented changes add a preview marker and media in_use boolean to successful responses. Post/page/custom-post-type, media, orphan-media, and score lists now return candidate windows with items, page, per_page, and next_page instead of exact total/total_pages. Continue until next_page is null, including after empty or short windows. Existing roles and object/key permissions still apply; per_page caps candidates at 100, not visible results. Post/page/custom-post-type and revision lists default to fields:"summary", which omits content only. Request fields:"full" for unchanged stored content. Excerpts and other values are unchanged; get/write responses stay full. These are not transactional snapshots or constant-time database queries, and summary payloads have no universal byte limit. Orphan-reference queries are batched over bounded candidates; scan errors still block forced media deletion. Authorized records include untrusted_fields, an array of field names relative to that record. Summary output never marks omitted content. Markers preserve stored values and nested maps; they do not sanitize data, grant capabilities, prove human approval, or guarantee prompt-injection prevention. Compact trash results and errors remain unmarked. Pagination whose offset or successor cannot fit a PHP integer is rejected before querying. Candidate/priming SQL failures return an error, not an empty end-of-list. Fresh SQL failures invalidate the current site's post-query cache generation to prevent cached false empty results; normal successful-query caching is unchanged. Failures are retained even when later native priming reads clear the last database error. The check adds no queries and preserves zero-query cache hits with stale errors.
Any MCP client that can reach your site through the MCP Adapter works. This includes Claude (Desktop and Code), ChatGPT, GitHub Copilot, Gemini CLI, Windsurf, and Codex. Most local clients connect through the @automattic/mcp-wordpress-remote bridge.
No. This plugin extends the MCP Adapter plugin and depends on it for MCP transport and ability registration.
It requires a WordPress site where custom plugins can be installed. Self-hosted WordPress and managed hosts that allow custom plugins should work. WordPress.com Free, Personal, and Premium plans do not allow custom plugin installation.
Use a dedicated Editor account for normal content workflows: posts, pages, taxonomy, comments, media, revisions, content blocks, and content hygiene. Comment updates, approval, trash, and spam actions require both moderate_comments and edit_comment for the specific comment. A custom moderator role also needs the mapped edit permissions for the comment's post; owning a post alone does not remove the moderate_comments requirement. Missing-comment failures uniformly use not_found code and reason. Invalid or nonpositive IDs cannot fall back to a global comment or silently select another ID. Listing and reply permissions are unchanged. Use a separate dedicated Administrator account only when you need Administrator-only workflows such as runtime environment details, plugin management, user access audits, site health, database health, performance status, backup status, security audits, or site-wide SEO overview.
A dedicated account limits the agent to the role you choose, makes activity easier to attribute, and lets you revoke access by deleting the application password or user.
No. Structural SEO checks still work without either plugin. Yoast-specific metadata and score abilities require Yoast SEO. SEOPress-specific metadata inspection and writes require SEOPress.
Only for the optional Site Kit status, module, permission, and PageSpeed abilities. The integration is a read-only compatibility adapter over Site Kit's internal REST routes, which Google does not publish as a supported third-party API. It checks route availability at runtime and preserves Site Kit's own setup, dashboard-sharing, and datapoint permissions. Module, permission, and PageSpeed abilities require the WordPress read capability before any upstream work, plus the exact Site Kit route's permission check. Missing providers, routes, or callable permission checks deny access. Read alone is not sufficient; a Subscriber is allowed only when Site Kit also authorizes that user. Status retains its separate manage_options requirement. The official Site Kit 1.187.0 routes were inspected without Google data calls on a disposable installation. Module-list and permission routes require Site Kit splash or dashboard access; this version's PageSpeed route resolves to Site Kit setup or post-insights access. Effective checks also depend on setup, authentication, sharing, and network state. This does not establish compatibility for every historical version or grant ordinary Subscribers dashboard access. See the repository README for exact capability names and version-specific sources. PageSpeed requests are limited to URLs on the current site and are processed by Google's PageSpeed service through Site Kit. Responses omit OAuth scopes and proxy details, module owner identities, screenshots, third-party entity lists, and full Lighthouse payloads.
Yes. The webmaster verification check requires read and checks public homepage meta tags, Bing XML, DNS TXT, robots.txt, and sitemap reachability without Google or Bing API credentials. It does not confirm account ownership. WordPress-only Site Kit installation and activation details require activate_plugins; other callers receive neither private projection, and their summary counts only public checks.
Public results, including failures and unknowns, are cached for 60 seconds per site, home URL, and result schema. Warm calls reuse HTTP/DNS results; privileged plugin state is inspected separately on each call and never stored in the public cache. Concurrent cold misses or early cache eviction can repeat requests, so this is not a strict rate limit.
Write operations go through WordPress APIs and capability checks. Posts, pages, and custom post type items move to trash rather than being permanently deleted. Media deletion is permanent. Block and partial-content patching can use hashes so stale or ambiguous edits fail safely. In 3.0, permanent media/term deletion and both bulk operations require confirm:true. Bulk dry_run:true performs the same eligibility checks without writes, including when trash is disabled, and adds data.dry_run:true. Strings and numbers cannot substitute for boolean safety flags. Batch success does not mean every item succeeded; inspect successes and failures. Media deletion checks known featured-image and literal content URL/GUID references; a hit requires force:true. Permission and reference-query failures still deny forced deletion. The successful in_use flag describes known references, not universal non-use: external sites, custom storage, transformed URLs, and concurrent edits can be missed. These interlocks neither grant capabilities nor prove human approval; clients still need independent authorization for the exact action and IDs. Publishing, scheduling, or marking content private requires the relevant WordPress publish capability. User login/email fields and author login names are not exposed to lower-privilege list responses.
The standalone get-post-meta and update-post-meta abilities require edit_post_meta for the actual object and key; delete-post-meta requires delete_post_meta. All three also require edit_post and preserve the existing protected-key eligibility rules. Upserts include absent and unchanged values, and deletions check authorization even when the key is absent. Explicit denied reads return forbidden; listings omit denied keys. Requiring edit permission for reads is a conservative plugin policy, not a general WordPress read-meta capability. Global/subtype registrations and effective WordPress capability filters are respected, including explicit primitive grants from providers. The compatibility default for genuinely unregistered supported SEO keys does not bypass those filters. Successful response shapes are unchanged. In 3.0, post/page/custom-post-type create and general update reject metadata containers and all SEO aliases before writes, even when empty or null. Create a draft without metadata, write each exact key through update-post-meta, verify the results, and then publish with a plain update. These separate calls are not atomic; keep the draft unpublished if any write fails. Separate SEO inspection and analysis omit denied fields and report unavailable_fields; they never read a denied key. Analysis skips unevaluable checks, and score pagination includes only authorized objects and score keys. Generated Yoast head output is unavailable; URL-only head requests return unsupported. This conservative read policy requires effective edit_post and edit_post_meta, not just permission to see the public page. SEO overview samples at most 100 published posts/pages ordered by ID. Missing counts and up to 20 IDs per field refer only to authorized sampled observations; observed_count is that field's authorized denominator, not a sitewide count. Zero observations are no evidence, not an all-clear. See the repository's 3.0 migration guide for every removed alias and its exact metadata key.
Yes. Standalone post metadata and media titles, captions, and alt text preserve backslashes through WordPress storage. Use normal JSON escaping, not an extra WordPress slashing layer. Existing text, HTML, and SEO-provider sanitization still applies; responses reflect sanitized stored values. Use update-post-meta with an exact key: public keys also support JSON-compatible arrays and objects; supported protected SEO keys retain scalar normalization.
A positive parent must exist, have the same hierarchical post type, and be editable by the connected account. A requested parent cannot create a cycle or lead into an existing cyclic hierarchy. Invalid or unauthorized assignments fail before any of the request's content, status, metadata, or taxonomy changes are saved. Set parent to 0 to detach an item. Omit parent to leave it unchanged on update. Reassigning the same parent still requires permission to edit that parent, but not every ancestor. Custom post types use their registered edit capability and WordPress capability filters. In 3.0, built-in posts and nonhierarchical custom post types reject any supplied parent field, including zero or null. Omit it on those types. Pages and hierarchical custom post types retain detach-to-zero and omitted-parent behavior, with the existing authorization and cycle checks.
3.0 closes fixed-property input objects and validates types, exact enums, required fields, numeric bounds, and array items before raw permission or execute callbacks. Unknown keys, numeric strings used as IDs, coerced booleans, and unadvertised null values are refused. Omit optional values to retain defaults. Input-free abilities accept omitted input or an empty object. Registered execution retains core input validation and then applies strict types before permissions, so numeric-string IDs and boolean-like flags report invalid_input rather than permission denial. Direct destructive preflight reasons and real capability denials are unchanged. Core normalization and lifecycle hooks remain active. Registered permission preflight honors a declared object-root default for omitted or null input, including empty database-health requests normalized by the Adapter. It does not replay normalization filters, grant capabilities, expose table names, coerce non-null inputs, or default nested null values. Directly invoked raw callbacks keep their existing strict checks. Standalone metadata JSON values and dynamic registered-taxonomy maps remain open where intended; existing metadata and taxonomy authorization still applies. WordPress handles other schema keywords such as URI formats. Output schemas are deferred to avoid constraining legitimate provider/error response shapes. No capabilities or external services are added.
Image URL uploads require upload_files and, when attaching to a post or page, edit_post for that object. The existing WordPress maximum upload size is enforced during streaming, with at most one extra sentinel byte in the temporary file and cancellation of oversized responses. Actual file size, allowed image MIME, HTTP integrity checks, and basic PNG/JPEG/GIF headers are checked before attachment creation. Generic HTTP Content-Type headers alone do not reject valid images. Invalid, zero, or overflowing configured limits fail explicitly. WordPress safe HTTP redirects, TLS checks, and Content-MD5 verification remain in use. The plugin also checks resolved IPv4/IPv6 answers and DNS aliases for the initial URL and redirect targets. Private/local addresses and failed, cyclic, or excessive alias resolution are rejected. IPv6 literals and AAAA-only hosts remain unsupported. Core's same-site exception does not bypass the plugin's private-address checks. These checks do not pin DNS or eliminate the race between DNS validation and connection. The byte limit is per response, not a total network or CPU budget: socket buffering and compressed decoding can exceed it before cancellation, while temporary file bytes stay bounded. Core transport differences for compressed/chunked images remain. Additional image formats enabled by WordPress filters still use core MIME handling.
Posts, pages, and custom post types require a nonempty scheduled_date when creating or newly requesting future status. The date must be valid and at least 60 seconds ahead when validated. Malformed calendar/time values, missing dates, and dates too close to now fail before content, metadata, or terms are written. Errors use success:false, code invalid_input, and reason invalid_scheduled_date, missing_scheduled_date, or scheduled_date_too_soon. An edit to an already-scheduled item may omit the date to retain its valid stored local/GMT dates; its GMT date must still meet the cutoff. Near-now/overdue schedules require a new safe date or an explicit nonfuture status. Changing the site timezone does not cause stored dates to be rewritten or rejected solely because they no longer match the current timezone. Prefer ISO 8601 with Z or an explicit offset and a comfortably future time. A normal clock tick between validation and WordPress's later check can cross the 60-second boundary; this is not an atomic status guarantee. WordPress and other plugins still control persistence hooks and cron execution. Legacy relative dates and offset-less parsing remain supported. Offset-less values normally mean UTC, not site-local time. Named-timezone DST folds/gaps retain PHP's resolution; explicit offsets preserve their instant. A valid date supplied for other statuses still sets date arguments under normal WordPress rules, including the existing zero-GMT draft/pending update reset and publish-to-future conversion.
Editors and Administrators can manage them with WordPress's default capabilities. Create/update uses the registered taxonomy's edit_terms capability; deletion uses delete_terms. Updating or deleting an existing term also checks WordPress's edit_term or delete_term capability for that term, including site-specific policy filters. Custom taxonomy capability mappings are respected instead of always requiring manage_categories. Creation retains management-level access rather than allowing everyone who can assign tags. The default category cannot be deleted under core's permission mapping. Failed or refused deletion returns an error rather than deleted: true, even when site filters override the initial permission denial. Ordinary term deletion remains permanent and follows WordPress's relationship reassignment behavior. Read permissions and successful response shapes are unchanged.
Block and section patches sanitize only the replacement fragment, not the entire rebuilt body. Exact patches compare old_content against the original raw content, including markup that would be removed by HTML sanitization. Both abilities still require permission to edit the specific object. WordPress's normal save filters remain active. Existing iframe, script, style, form, SVG, and event-attribute markup can be preserved only when the caller has effective unfiltered_html permission. Multisite, DISALLOW_UNFILTERED_HTML, and capability policies can deny that permission even to an Administrator. Replacement fragments are always filtered, and full-content updates still sanitize all supplied content. Block and heading patches retain WordPress's existing parse/serialize normalization, including noncanonical block delimiters and empty freeform separators. Exact patches leave surrounding raw bytes alone, subject to WordPress's save filters. On a test site, compare the untouched block hashes from list-content-blocks before and after patching a neighboring block.
When EMPTY_TRASH_DAYS is 0 or another falsy value, post, page, and custom post type trash abilities refuse with trash_disabled before changing the item. Bulk post trash reports a failure for each authorized ID rather than a false success; inspect its per-ID failures and counts even when the summary itself succeeds. Missing items, wrong types, and permission failures keep their existing precedence. There is no permanent-delete override. Comment trash and comment updates with status "trash" still retain the comment row and set its status through WordPress's comment-status API. They do not use the post-trash deletion fallback.
Ability counts vary with eligible custom post types and the deployed plugin version. Check the registered names and version on the connected site before assuming it needs an update.
No. Retrieved content and metadata remain untrusted data even when the response is JSON, authenticated, read-only, or capability-checked. They cannot authorize later changes or sending data elsewhere. Use a dedicated account with the least privileges needed, bounded selections, independent previews/diffs, explicit client-side approval for dangerous actions and destinations, and trustworthy backups. Sanitization, annotation hints, or a model-supplied confirmation value cannot prove human approval or guarantee prompt-injection prevention. SEO Analyze Post uses the exact diagnostics "Focus keyword found in title." and "Focus keyword not found in title." Authorized stored focus keywords remain in their existing Yoast/SEOPress metric fields, not these messages. 3.0 metadata authorization omits denied fields and skips unevaluable checks; markers do not undo that policy. 3.0 field markers, annotation hints, and confirmation interlocks are defense-in-depth, not a security boundary, capability check, content filter, or prompt-injection guarantee. Optional text-only content_format output is not implemented. See the Agent threat model and Response format. A successful MCP gateway response does not necessarily mean the inner ability succeeded.
Each affected successful record adds an array of unique field names relative to that record, not paths or a global list. Only present fields are named, including empty and null values. Marker addition retains original response values and types exactly, including HTML and block delimiters, while preserving existing input sanitization and normalizers. Missing or redacted fields are never restored. Covered records include post/page/custom-post-type titles, bodies, excerpts, slugs, URLs and author display names; revision text and author display names; block names, text, HTML and attributes; comment text and author identity fields; media titles, captions, alt text, URLs and filenames; user profiles and privileged audit fields; authorized SEO metrics, provider metadata containers and score records; and sitemap URL/entries and robots URL records. Container markers leave nested maps unchanged. Canonical errors and diagnostic error subrecords have no markers. Unmarked content is not guaranteed trusted. Content-hygiene lists mark title and url on each orphaned-media and missing-featured-image item, and title, url and author_name on each stuck-scheduled item. Existing values, list ordering, authorizations, reference checks and query failures remain unchanged. Standalone get-post-meta marks meta on its containing data record. Standalone update-post-meta marks meta_key, previous_value and current_value on its data record. All nested stored maps remain unchanged, as do object/key authorization and protected-key eligibility. The existing comment normalizer emits author email/URL under its existing permissions; there is no new field-level privacy gate. The separate user list/get login/email privacy gate remains intact. Standalone delete-post-meta marks meta_key on its data record without changing delete authorization. patch-content-block marks content on its data record; patch-post-content marks present heading_text on data.target, with an empty untrusted_fields array for exact-match targets. The nested normalized post remains marked. SEO/site overview marks present url/entries on sitemap and url on robots_txt. Original values and types are unchanged. Permissions and privacy remain unchanged. Content and media retain their object/status policies. Comment listing requires moderate_comments; replies require edit_posts plus parent edit_post; moderation requires moderate_comments plus edit_comment. Markers do not add comment email/URL redaction. User lookup requires list_users, with login/email only when edit_user for the target or edit_users permits them; user access audits require edit_users. SEO keys require effective object/key authorization, and unavailable_fields/unevaluable_checks remain intact. Generated Yoast head output stays unavailable, URL-only inspection stays unsupported, and no provider head calls are made. Markers accompany data through both gateway and individual tools. The default tools/list advertises three gateway tools, not per-ability hints; use mcp-adapter-get-ability-info for the ability metadata. Compare actual Adapter readOnlyHint, destructiveHint and idempotentHint against registered readonly, destructive and idempotent values on individual tools. The assessment distinguishes measured pre-release annotation proof from release-package validation. For exact field names, examples and disposable-site verification, see the repository README's "Untrusted result fields (3.0)" section.
The complete ability reference and client setup guide are maintained at: https://www.virtuallyboring.com/webmastery-site-toolkit-for-mcp/
Both abilities require manage_options. The security audit's ssl finding checks the configured public home option, respecting normal option filters and WP_HOME: recognized HTTPS passes and HTTP fails. Missing/unsupported schemes or hosts, whitespace/control characters, malformed percent escapes, and invalid authority syntax warn as unknown. This local syntax guard preserves local names, Unicode/IDN forms, escaped components, and bracketed IPv6 (including escaped zone IDs) or IPvFuture literals. It is not a complete URL, DNS-name, or internationalized-name validator and imposes no address-routability policy. The MCP request scheme and admin-only TLS policy do not determine this finding. It does not verify certificates, reachability, redirects, or the final filtered front-end URL. Debug-log findings omit filesystem paths. Enabled logging warns that access is unverified, even when a neighboring .htaccess file exists or the location is outside wp-content; neither proves that web access is denied. Disabled logging still passes. Necessary logging need not be disabled merely because it is enabled. Database query failures retain the contextual database_health_query_failed reason without raw SQL/server error details, leaving WordPress's own logging unchanged. In 3.0, table-size reports use core logical names (such as posts) and response-local opaque custom labels (such as custom_table_1), with an is_core_table boolean. The default reveals neither the configured prefix nor custom/plugin names. Labels are not stable across reports. Explicit include_table_names: true deliberately sends raw table identifiers to the model provider; it still requires manage_options. Only actual booleans are accepted, including in direct execution. Both modes retain counts, bytes, ordering, and current-prefix scope and never return passwords, SQL errors, or filesystem paths.
Report suspected vulnerabilities privately at https://github.com/DanielBoring/webmastery-site-toolkit-for-mcp/security/advisories/new rather than in public issues or support threads. Include affected versions, the ability, the minimum required role, and reproduction steps on a test site. Do not include credentials or private site data. Security fixes target the latest stable release. Reports receive a best-effort response without a guaranteed deadline. See https://github.com/DanielBoring/webmastery-site-toolkit-for-mcp/security/policy for the full policy.