Skip to content

feat(block-mcp): add list_binding_sources tool - #55

Merged
zackkatz merged 11 commits into
developfrom
feature/block-32-list_binding_sources-enumerate-registered-block-binding
Jul 22, 2026
Merged

feat(block-mcp): add list_binding_sources tool#55
zackkatz merged 11 commits into
developfrom
feature/block-32-list_binding_sources-enumerate-registered-block-binding

Conversation

@zackkatz

@zackkatz zackkatz commented Jul 22, 2026

Copy link
Copy Markdown
Member

What changed

New list_binding_sources tool enumerates registered block bindings sources — what a block's metadata.bindings attribute can reference to pull an attribute value dynamically (e.g. core/post-meta, core/pattern-overrides).

  • Block_Registry::get_binding_sources() (wordpress-plugin/gk-block-mcp/includes/class-block-registry.php) wraps get_all_registered_block_bindings_sources() behind a function_exists() guard (the Block Bindings API requires WordPress 6.5+). Below 6.5 it returns {sources: [], note: 'Block bindings require WordPress 6.5+.'}. Each live source formats as {name, label, uses_context?} (uses_context omitted when the source declares none).
  • REST: new GET /binding-sources route, check_permissions, no args.
  • src/client.ts: getBindingSources().
  • src/tools/discovery.ts: new list_binding_sources tool, no input args, READ_ANNOT.
  • src/agent-guide.ts: new "Block bindings" section — check list_binding_sources before wiring metadata.bindings to a source.
  • README.md: new Discovery row.
  • Regenerated tools.manifest.json (27 → 28 tools) + assets/mcp-server/index.cjs.
  • Bumped the two hardcoded tool-count fixtures in tests/Abilities/AbilitiesRegistryTest.php (27→28 manifest total, 24→25 non-Yoast ability ids, 27→28 Yoast-active ability ids) that the new tool pushed out of sync.

Acceptance criteria

  • core/post-meta and core/pattern-overrides present on the test install (PHP + live smoke)
  • Pre-6.5 fallback shape/message unit-covered (the function_exists branch itself can't be flipped live on a 6.5+ test environment — documented in the test)
  • TS: dispatch (list_binding_sourcesclient.getBindingSources(), no args) + response passthrough (sources, note)
  • Docs: README row, agent-guide section, manifest + bundle regenerated

Gate output

npm test        → Test Files 53 passed (53) · Tests 820 passed (820)
npm run build    → dist/index.cjs 3.6mb, bundle copied to wordpress-plugin/gk-block-mcp/assets/mcp-server/index.cjs
node scripts/export-abilities-manifest.mjs && git diff --exit-code tools.manifest.json → clean, no drift
composer test    → OK (1351 tests, 17984 assertions) · OK (28 tests, 82 assertions) [yoast] · OK (11 tests, 25 assertions) [adapter] · OK (5 tests, 37 assertions) [multisite]
composer lint    → 0 errors, 0 warnings
composer analyze → [OK] No errors

Siteminter smoke

Site blockmcp-a (Docker/Siteminter, http://localhost:8960, gk-block-mcp mounted from this worktree; branch checked out live via symlink), real HTTP request with a WP Application Password:

$ curl -s -u "admin:<app-password>" "http://localhost:8960/wp-json/gk-block-api/v1/binding-sources" | jq
{
  "sources": [
    { "name": "core/pattern-overrides", "label": "Pattern Overrides", "uses_context": ["pattern/overrides"] },
    { "name": "core/post-data", "label": "Post Data", "uses_context": ["postId", "postType"] },
    { "name": "core/post-meta", "label": "Post Meta", "uses_context": ["postId", "postType"] },
    { "name": "core/term-data", "label": "Term Data", "uses_context": ["termId", "taxonomy"] },
    { "name": "twentytwentyfive/format", "label": "Post format name" }
  ]
}

core/post-meta and core/pattern-overrides both present, confirming the real endpoint against a live WordPress install.

Fixes BLOCK-32
https://linear.app/gravitykit/issue/BLOCK-32

https://claude.ai/code/session_013YcSbKroBJjPanX3okQrT3

💾 Build file (5d6a70e).

Summary by CodeRabbit

  • New Features
    • Added list_binding_sources to show registered block binding sources (including context usage where supported).
    • Added a read-only REST endpoint for binding sources.
    • Expanded the exported tools manifest with template abilities (list/get/update/reset), now included in the abilities manifest output.
  • Documentation
    • Updated the agent guide and README (plus embedded MCP docs) with “Block bindings” instructions and compatibility notes.
  • Tests
    • Added coverage for the discovery tool and new binding-sources REST responses.

@linear-code

linear-code Bot commented Jul 22, 2026

Copy link
Copy Markdown

BLOCK-32

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The PR adds binding-source discovery through the WordPress REST API and MCP tools, documents its use, adds coverage for supported and fallback responses, and includes template tools in the generated abilities manifest.

Changes

Binding source discovery

Layer / File(s) Summary
Binding source API
wordpress-plugin/gk-block-mcp/includes/class-block-registry.php, wordpress-plugin/gk-block-mcp/includes/class-rest-controller.php
Adds guarded binding-source collection and a permission-protected REST endpoint with fallback notes for unsupported WordPress versions.
Discovery client and tool wiring
src/client.ts, src/tools/discovery.ts, wordpress-plugin/gk-block-mcp/assets/mcp-server/index.cjs, src/__tests__/helpers/mock-client.ts
Adds typed client retrieval, the read-only list_binding_sources tool, request routing, and mock support.
Validation and guidance
src/__tests__/tools/discovery/list_binding_sources.test.ts, wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php, src/agent-guide.ts, README.md, wordpress-plugin/gk-block-mcp/assets/mcp-server/index.cjs
Tests response passthrough, source metadata, fallback behavior, annotations, and documents binding-source verification.

Template abilities manifest

Layer / File(s) Summary
Template tool manifest export
scripts/export-abilities-manifest.mjs, wordpress-plugin/gk-block-mcp/includes/abilities/tools.manifest.json, wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php
Includes TEMPLATE_TOOLS during manifest generation, adds template and binding-source abilities, and updates registry-count expectations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant MCPServer
  participant RESTAPI
  participant BlockRegistry
  Caller->>MCPServer: list_binding_sources
  MCPServer->>RESTAPI: GET /binding-sources
  RESTAPI->>BlockRegistry: get_binding_sources()
  BlockRegistry-->>RESTAPI: sources and optional note
  RESTAPI-->>MCPServer: response payload
  MCPServer-->>Caller: sources and optional note
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding the new list_binding_sources MCP tool.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/block-32-list_binding_sources-enumerate-registered-block-binding

Comment @coderabbitai help to get the list of available commands.

@zackkatz

Copy link
Copy Markdown
Member Author

Reopening to retrigger CI (Tests workflow never fired on initial open).

@zackkatz zackkatz closed this Jul 22, 2026
@zackkatz zackkatz reopened this Jul 22, 2026
@zackkatz
zackkatz force-pushed the feature/block-32-list_binding_sources-enumerate-registered-block-binding branch from 3abdaea to 57b7c8b Compare July 22, 2026 22:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php (1)

38-65: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Assert the newly exported tool names.

assertCount( 30, … ) passes if any of list_binding_sources, list_templates, or get_template is replaced by another entry. Add explicit assertions for all three to pin this manifest-export contract.

Proposed test addition
 		$this->assertContains( 'get_page_blocks', $names );
 		$this->assertContains( 'edit_block_tree', $names );
 		$this->assertContains( 'site_editor_context', $names );
+		$this->assertContains( 'list_binding_sources', $names );
+		$this->assertContains( 'list_templates', $names );
+		$this->assertContains( 'get_template', $names );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php`
around lines 38 - 65, Update test_manifest_lists_all_block_mcp_tools in
AbilitiesRegistryTest to explicitly assert that the manifest tool names include
list_binding_sources, list_templates, and get_template. Keep the existing count
and assertions unchanged.
🧹 Nitpick comments (1)
wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php (1)

21-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add contract-focused docblocks for every test.

Three test methods have none, and the existing fallback docblock is narrative. State the asserted contract, why it exists, and the failure/regression it prevents.

Also applies to: 37-44, 53-60, 62-75

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php` around lines
21 - 35, Add contract-focused docblocks to every test method in the relevant
test class, including test_core_post_meta_and_pattern_overrides_are_registered
and the tests at the referenced ranges. Each docblock must state the behavior
being asserted, why that contract exists, and the failure or regression it
prevents; replace the existing narrative fallback docblock with the same
contract-oriented structure without changing test logic.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/tools/discovery.ts`:
- Around line 213-214: Update the list_binding_sources handler in the tool
dispatch to preserve the raw getBindingSources response while adding a guidance
field. The guidance must tell agents to verify a binding source before using
metadata.bindings and to avoid bindings when the API is unavailable.

In `@wordpress-plugin/gk-block-mcp/includes/class-rest-controller.php`:
- Around line 1287-1292: Update the docblock for the public
get_binding_sources() method to include the required `@since` 2.2.0 annotation,
preserving the existing endpoint description and return declaration.

In `@wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php`:
- Around line 44-51: Update
test_pre_65_fallback_shape_matches_the_guarded_branch() to exercise the actual
Block_Registry::get_binding_sources() or controller response instead of
asserting a locally constructed fallback array. Add a controllable seam for the
WordPress version/capability check, force the unsupported pre-6.5 branch, and
assert that the real response contains empty sources and the expected
compatibility note.

---

Outside diff comments:
In `@wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php`:
- Around line 38-65: Update test_manifest_lists_all_block_mcp_tools in
AbilitiesRegistryTest to explicitly assert that the manifest tool names include
list_binding_sources, list_templates, and get_template. Keep the existing count
and assertions unchanged.

---

Nitpick comments:
In `@wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php`:
- Around line 21-35: Add contract-focused docblocks to every test method in the
relevant test class, including
test_core_post_meta_and_pattern_overrides_are_registered and the tests at the
referenced ranges. Each docblock must state the behavior being asserted, why
that contract exists, and the failure or regression it prevents; replace the
existing narrative fallback docblock with the same contract-oriented structure
without changing test logic.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5a6b5760-236c-4237-a6b1-37fe93823c53

📥 Commits

Reviewing files that changed from the base of the PR and between 87c9900 and 57b7c8b.

📒 Files selected for processing (13)
  • README.md
  • scripts/export-abilities-manifest.mjs
  • src/__tests__/helpers/mock-client.ts
  • src/__tests__/tools/discovery/list_binding_sources.test.ts
  • src/agent-guide.ts
  • src/client.ts
  • src/tools/discovery.ts
  • wordpress-plugin/gk-block-mcp/assets/mcp-server/index.cjs
  • wordpress-plugin/gk-block-mcp/includes/abilities/tools.manifest.json
  • wordpress-plugin/gk-block-mcp/includes/class-block-registry.php
  • wordpress-plugin/gk-block-mcp/includes/class-rest-controller.php
  • wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php
  • wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php

Comment thread src/tools/discovery.ts
Comment on lines +213 to +214
case 'list_binding_sources':
return await client.getBindingSources();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Enrich the tool response with binding guidance.

This handler passes through { sources, note? } without instructing agents to verify a source before using metadata.bindings, or warning them not to use bindings when the API is unavailable. Add a guidance field while preserving the raw response fields. As per coding guidelines, MCP tool responses must include AI-friendly guidance; this also matches the PR objective.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/tools/discovery.ts` around lines 213 - 214, Update the
list_binding_sources handler in the tool dispatch to preserve the raw
getBindingSources response while adding a guidance field. The guidance must tell
agents to verify a binding source before using metadata.bindings and to avoid
bindings when the API is unavailable.

Source: Coding guidelines

Comment on lines +1287 to +1292
/**
* GET /binding-sources
*
* @return \WP_REST_Response|\WP_Error
*/
public function get_binding_sources() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Add the required @since annotation.

get_binding_sources() is a new shipped public method, but its docblock has no @since 2.2.0. As per coding guidelines, public production methods must include a version annotation; the retrieved learning confirms this requirement applies to public members.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/includes/class-rest-controller.php` around
lines 1287 - 1292, Update the docblock for the public get_binding_sources()
method to include the required `@since` 2.2.0 annotation, preserving the existing
endpoint description and return declaration.

Sources: Coding guidelines, Learnings

Comment on lines +44 to +51
public function test_pre_65_fallback_shape_matches_the_guarded_branch() {
$fallback = array(
'sources' => array(),
'note' => __( 'Block bindings require WordPress 6.5+.', 'gk-block-mcp' ),
);
$this->assertSame( array(), $fallback['sources'] );
$this->assertSame( 'Block bindings require WordPress 6.5+.', $fallback['note'] );
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Exercise the actual compatibility fallback.

This test only validates a locally constructed array, so it passes if Block_Registry::get_binding_sources() changes or removes its fallback. Add a controllable capability-check seam and assert the real registry/controller response for the unsupported branch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php` around lines
44 - 51, Update test_pre_65_fallback_shape_matches_the_guarded_branch() to
exercise the actual Block_Registry::get_binding_sources() or controller response
instead of asserting a locally constructed fallback array. Add a controllable
seam for the WordPress version/capability check, force the unsupported pre-6.5
branch, and assert that the real response contains empty sources and the
expected compatibility note.

Source: Coding guidelines

zackkatz added 11 commits July 22, 2026 19:00
…dings sources

Block_Registry::get_binding_sources() wraps
get_all_registered_block_bindings_sources() behind a function_exists
guard (Block Bindings requires WP 6.5+); below that it returns an
empty sources array with an explanatory note. Each source reports
{name, label, uses_context?}.

Claude-Session: https://claude.ai/code/session_013YcSbKroBJjPanX3okQrT3
client.getBindingSources() → GET /binding-sources; new no-arg
list_binding_sources discovery tool; agent-guide notes to check
registered sources before wiring metadata.bindings.

Claude-Session: https://claude.ai/code/session_013YcSbKroBJjPanX3okQrT3
Discovered while rebasing BLOCK-32 onto develop: the read-only
list_templates/get_template tools (merged in #52) are wired into
src/index.ts but scripts/export-abilities-manifest.mjs never imported
TEMPLATE_TOOLS, so they were silently absent from the WordPress
Abilities API surface (register_abilities() only reads the manifest).
Both tools are readOnlyHint:true so they classify correctly as `read`
permission with no further generator changes.

Claude-Session: https://claude.ai/code/session_013YcSbKroBJjPanX3okQrT3
…plates work

develop now includes #52 (list_templates/get_template). Combined with
this branch's list_binding_sources and the manifest-generator fix, the
full tool count is 30 (27 baseline + 2 template tools + 1 new).

Claude-Session: https://claude.ai/code/session_013YcSbKroBJjPanX3okQrT3
develop now also includes update_template/reset_template (#56, same
TEMPLATE_TOOLS array my manifest-generator fix already covers).

Claude-Session: https://claude.ai/code/session_013YcSbKroBJjPanX3okQrT3
@zackkatz
zackkatz force-pushed the feature/block-32-list_binding_sources-enumerate-registered-block-binding branch from 57b7c8b to 5d6a70e Compare July 22, 2026 23:04

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
wordpress-plugin/gk-block-mcp/includes/abilities/tools.manifest.json (1)

178-195: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Grammar nit in tool label.

"label": "List block bindings sources" reads awkwardly — "bindings" used as an adjective before "sources" should be singular: "List block binding sources" (the description on the next line already uses "block bindings sources" correctly as the noun phrase describing what block binding sources are, but the label itself should read as "binding sources").

✏️ Suggested label fix
-      "label": "List block bindings sources",
+      "label": "List block binding sources",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/includes/abilities/tools.manifest.json` around
lines 178 - 195, Update the label in the list_binding_sources manifest entry
from “List block bindings sources” to “List block binding sources”; leave the
description and all other metadata unchanged.
wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php (1)

49-66: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin the 5 newly-added tool names, not just the count.

test_manifest_lists_all_block_mcp_tools asserts assertCount(32, ...) plus 3 pre-existing tool names, but doesn't assert that list_binding_sources, list_templates, get_template, update_template, and reset_template are actually present. A future manifest regeneration that drops one of these while adding an unrelated tool would keep the count at 32 and this test green, silently regressing exactly the scenario the docblock warns about ("loads a stale set because a tool was added/removed... without regenerating it").

✅ Suggested additional assertions
 		$names = wp_list_pluck( $manifest['tools'], 'name' );
 		$this->assertContains( 'get_page_blocks', $names );
 		$this->assertContains( 'edit_block_tree', $names );
 		$this->assertContains( 'site_editor_context', $names );
+		$this->assertContains( 'list_binding_sources', $names );
+		$this->assertContains( 'list_templates', $names );
+		$this->assertContains( 'get_template', $names );
+		$this->assertContains( 'update_template', $names );
+		$this->assertContains( 'reset_template', $names );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php`
around lines 49 - 66, Update test_manifest_lists_all_block_mcp_tools in
AbilitiesRegistryTest to assert that the manifest tool names also contain
list_binding_sources, list_templates, get_template, update_template, and
reset_template. Keep the existing count and pre-existing tool assertions
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php`:
- Around line 21-35: Add contract-focused docblocks to
test_core_post_meta_and_pattern_overrides_are_registered(),
test_live_registry_never_returns_the_fallback_note(), and
test_uses_context_present_only_when_declared(). Each docblock must state the
expected contract, the regression being pinned, and the failure mode; move the
rationale from the inline comment near the latter test into its method docblock
and remove the redundant inline comment.
- Around line 21-35: Update
test_core_post_meta_and_pattern_overrides_are_registered and the related
assertions to branch on the actual get_binding_sources() response: validate the
WordPress 6.5+ sources shape when sources are present, and validate the
WordPress 6.0–6.4 fallback contains an empty sources array and a note. Ensure
both supported response shapes are covered without unconditionally requiring the
newer source entries.
- Around line 62-75: Add a negative assertion in
test_uses_context_present_only_when_declared: identify a known binding source
whose metadata omits context and assert that its entry in $by_name does not have
the uses_context key, while preserving the existing core/post-meta positive
assertions.

---

Nitpick comments:
In `@wordpress-plugin/gk-block-mcp/includes/abilities/tools.manifest.json`:
- Around line 178-195: Update the label in the list_binding_sources manifest
entry from “List block bindings sources” to “List block binding sources”; leave
the description and all other metadata unchanged.

In `@wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php`:
- Around line 49-66: Update test_manifest_lists_all_block_mcp_tools in
AbilitiesRegistryTest to assert that the manifest tool names also contain
list_binding_sources, list_templates, get_template, update_template, and
reset_template. Keep the existing count and pre-existing tool assertions
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 88edd9e7-8a50-4e64-95b2-3a629a9e2478

📥 Commits

Reviewing files that changed from the base of the PR and between 57b7c8b and 5d6a70e.

📒 Files selected for processing (13)
  • README.md
  • scripts/export-abilities-manifest.mjs
  • src/__tests__/helpers/mock-client.ts
  • src/__tests__/tools/discovery/list_binding_sources.test.ts
  • src/agent-guide.ts
  • src/client.ts
  • src/tools/discovery.ts
  • wordpress-plugin/gk-block-mcp/assets/mcp-server/index.cjs
  • wordpress-plugin/gk-block-mcp/includes/abilities/tools.manifest.json
  • wordpress-plugin/gk-block-mcp/includes/class-block-registry.php
  • wordpress-plugin/gk-block-mcp/includes/class-rest-controller.php
  • wordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.php
  • wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/tests/helpers/mock-client.ts
  • src/tests/tools/discovery/list_binding_sources.test.ts
  • wordpress-plugin/gk-block-mcp/includes/class-block-registry.php
  • README.md
  • wordpress-plugin/gk-block-mcp/includes/class-rest-controller.php
  • src/client.ts
  • src/agent-guide.ts
  • scripts/export-abilities-manifest.mjs
  • src/tools/discovery.ts
  • wordpress-plugin/gk-block-mcp/assets/mcp-server/index.cjs

Comment on lines +21 to +35
public function test_core_post_meta_and_pattern_overrides_are_registered() {
$response = $this->controller->get_binding_sources();

$this->assertInstanceOf( \WP_REST_Response::class, $response );
$data = $response->get_data();
$names = wp_list_pluck( $data['sources'], 'name' );

$this->assertContains( 'core/post-meta', $names );
$this->assertContains( 'core/pattern-overrides', $names );

foreach ( $data['sources'] as $source ) {
$this->assertArrayHasKey( 'name', $source );
$this->assertArrayHasKey( 'label', $source );
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Add the required contract docblocks to every test method.

test_core_post_meta_and_pattern_overrides_are_registered(), test_live_registry_never_returns_the_fallback_note(), and test_uses_context_present_only_when_declared() lack docblocks describing the contract, regression being pinned, and failure mode. Move the rationale currently expressed in the inline comment at Line 71 into the method docblock.

As per coding guidelines, every test method must have a docblock stating its contract, why it exists, the regression it pins, and the failure mode.

Also applies to: 53-60, 62-75

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php` around lines
21 - 35, Add contract-focused docblocks to
test_core_post_meta_and_pattern_overrides_are_registered(),
test_live_registry_never_returns_the_fallback_note(), and
test_uses_context_present_only_when_declared(). Each docblock must state the
expected contract, the regression being pinned, and the failure mode; move the
rationale from the inline comment near the latter test into its method docblock
and remove the redundant inline comment.

Source: Coding guidelines


🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Make these assertions compatible with WordPress 6.0+

The plugin supports WordPress 6.0+, but these tests unconditionally require the WordPress 6.5 response shape. On WordPress 6.0–6.4, the guarded fallback should return empty sources plus a note, causing both tests to fail. Branch on the actual response and assert both supported shapes.

As per coding guidelines, the plugin supports WordPress 6.0+ and compatibility tests must cover the real supported behavior.

Also applies to: 53-60

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php` around lines
21 - 35, Update test_core_post_meta_and_pattern_overrides_are_registered and the
related assertions to branch on the actual get_binding_sources() response:
validate the WordPress 6.5+ sources shape when sources are present, and validate
the WordPress 6.0–6.4 fallback contains an empty sources array and a note.
Ensure both supported response shapes are covered without unconditionally
requiring the newer source entries.

Source: Coding guidelines

Comment on lines +62 to +75
public function test_uses_context_present_only_when_declared() {
$response = $this->controller->get_binding_sources();
$data = $response->get_data();

$by_name = array();
foreach ( $data['sources'] as $source ) {
$by_name[ $source['name'] ] = $source;
}

// core/post-meta declares uses_context (postId, postType).
$this->assertArrayHasKey( 'core/post-meta', $by_name );
$this->assertArrayHasKey( 'uses_context', $by_name['core/post-meta'] );
$this->assertIsArray( $by_name['core/post-meta']['uses_context'] );
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert the negative half of the uses_context contract.

The test only verifies that core/post-meta includes uses_context; it passes even if the implementation incorrectly adds uses_context to every source. Also assert that a known source whose metadata omits context does not contain the key.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@wordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php` around lines
62 - 75, Add a negative assertion in
test_uses_context_present_only_when_declared: identify a known binding source
whose metadata omits context and assert that its entry in $by_name does not have
the uses_context key, while preserving the existing core/post-meta positive
assertions.

@zackkatz
zackkatz merged commit 0b6db23 into develop Jul 22, 2026
9 checks passed
@zackkatz
zackkatz deleted the feature/block-32-list_binding_sources-enumerate-registered-block-binding branch July 22, 2026 23:09
zackkatz added a commit that referenced this pull request Jul 23, 2026
…_Executor (#59)

* test(abilities): list_binding_sources + create_pattern execution/gate parity [red]

Writes the failing tests for BLOCK-35 first, before any production code
change. Same class of gap Agent A flagged after #57/#55 merged and I fixed
for the templates group in #58: both tools are already in the manifest and
register as abilities (registration is manifest-driven, independent of
Tool_Executor), but neither has a Tool_Executor::execute() case, so both
400 "Unknown Block MCP tool" over the Abilities/MCP-Adapter transport
regardless of the caller's permissions.

New tests/Abilities/BindingSourcesAbilityTest.php: registration presence,
execution returns the {sources:[...]} shape, subscriber denial (read
permission parity with the rest of the discovery group), readonly
annotation.

New tests/Abilities/CreatePatternAbilityTest.php: registration presence,
execution creates a real wp_block post for an editor, subscriber denial
(base edit_posts check), and the actual gate-parity bug this issue exists
to fix — a Contributor (has edit_posts, lacks publish_posts) must be denied
by the ability exactly as REST_Controller::check_create_pattern_permissions()
denies the identical request over REST, because that permission callback
checks wp_block's create_posts capability (-> publish_posts) on top of the
base edit_posts check. A manifest permission of plain 'edit_post' would let
this actor through the ability while REST denies them. Also pins
check_create_pattern_permissions() denying the same Contributor directly,
and the create-pattern annotation (not readonly, not destructive).

tests/abilities-manifest.test.ts gains two assertions: list_binding_sources
already maps to 'read' (confirms no TS-side change needed there — the gap
is PHP-execution-only for this tool) and create_pattern must map to a new
'create_pattern' permission distinct from 'edit_post' (genuinely red).

Confirmed red:

  $ vendor/bin/phpunit -c tests/phpunit.xml tests/Abilities/
  Tests: 163, Assertions: 403, Failures: 3.
  (list_binding_sources execution: "Unknown Block MCP tool";
   create_pattern execution: "Unknown Block MCP tool";
   create_pattern Contributor-denial: got 'unknown_tool' instead of
   'ability_invalid_permissions' -- the wrong 'edit_post' permission branch
   let the Contributor through, then execution 400'd instead of the
   permission callback denying it)

  $ npm test -- tests/abilities-manifest.test.ts
  Tests  1 failed | 6 passed (7)
  (create_pattern permission: expected 'create_pattern', received 'edit_post';
   list_binding_sources permission already correctly 'read')

Claude-Session: https://claude.ai/code/session_013YcSbKroBJjPanX3okQrT3

* feat(abilities): wire list_binding_sources + create_pattern execution/gate parity [green]

Makes the BLOCK-35 red tests pass.

scripts/export-abilities-manifest.mjs: new CREATE_PATTERN permission bucket
mapping create_pattern to a 'create_pattern' permission key (checked before
the edit_post fallback). list_binding_sources needed no change -- its
readOnlyHint annotation already resolved to 'read'. Regenerated
tools.manifest.json (still 33 tools; only create_pattern's permission
value changes).

Abilities_Registry::check_tool_permission() gets a 'create_pattern' case
that delegates to REST_Controller::check_create_pattern_permissions() --
the same dedicated callback POST /patterns uses, which checks edit_posts
AND wp_block's create_posts capability (publish_posts). No gate logic is
re-implemented.

Tool_Executor::execute() gains dispatch cases + execute_list_binding_sources()
(delegates to REST_Controller::get_binding_sources()) and
execute_create_pattern() (delegates to REST_Controller::create_pattern(),
passing input through as the JSON body -- Pattern_Manager::create_pattern()
already validates title/content-blocks-XOR/sync_status/status, so no
duplicate validation belongs here), both via the existing call_controller()
pattern.

Also fixes a bug in the red commit's own test: create_pattern's response
key is `pattern_id`, not `id` (Pattern_Manager::create_pattern()'s actual
return shape) -- caught by an "Undefined array key" error on the first
green run, not a silent false pass.

Claude-Session: https://claude.ai/code/session_013YcSbKroBJjPanX3okQrT3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant