feat(block-mcp): add list_binding_sources tool - #55
Conversation
WalkthroughThe 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. ChangesBinding source discovery
Template abilities manifest
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
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
Reopening to retrigger CI (Tests workflow never fired on initial open). |
3abdaea to
57b7c8b
Compare
There was a problem hiding this comment.
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 winAssert the newly exported tool names.
assertCount( 30, … )passes if any oflist_binding_sources,list_templates, orget_templateis 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 winAdd 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
📒 Files selected for processing (13)
README.mdscripts/export-abilities-manifest.mjssrc/__tests__/helpers/mock-client.tssrc/__tests__/tools/discovery/list_binding_sources.test.tssrc/agent-guide.tssrc/client.tssrc/tools/discovery.tswordpress-plugin/gk-block-mcp/assets/mcp-server/index.cjswordpress-plugin/gk-block-mcp/includes/abilities/tools.manifest.jsonwordpress-plugin/gk-block-mcp/includes/class-block-registry.phpwordpress-plugin/gk-block-mcp/includes/class-rest-controller.phpwordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.phpwordpress-plugin/gk-block-mcp/tests/REST/BindingSourcesTest.php
| case 'list_binding_sources': | ||
| return await client.getBindingSources(); |
There was a problem hiding this comment.
🎯 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
| /** | ||
| * GET /binding-sources | ||
| * | ||
| * @return \WP_REST_Response|\WP_Error | ||
| */ | ||
| public function get_binding_sources() { |
There was a problem hiding this comment.
📐 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
| 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'] ); | ||
| } |
There was a problem hiding this comment.
🎯 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
…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
…nt fixtures to 28 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
…ns runner incident) 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
57b7c8b to
5d6a70e
Compare
There was a problem hiding this comment.
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 winGrammar 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 winPin the 5 newly-added tool names, not just the count.
test_manifest_lists_all_block_mcp_toolsassertsassertCount(32, ...)plus 3 pre-existing tool names, but doesn't assert thatlist_binding_sources,list_templates,get_template,update_template, andreset_templateare 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
📒 Files selected for processing (13)
README.mdscripts/export-abilities-manifest.mjssrc/__tests__/helpers/mock-client.tssrc/__tests__/tools/discovery/list_binding_sources.test.tssrc/agent-guide.tssrc/client.tssrc/tools/discovery.tswordpress-plugin/gk-block-mcp/assets/mcp-server/index.cjswordpress-plugin/gk-block-mcp/includes/abilities/tools.manifest.jsonwordpress-plugin/gk-block-mcp/includes/class-block-registry.phpwordpress-plugin/gk-block-mcp/includes/class-rest-controller.phpwordpress-plugin/gk-block-mcp/tests/Abilities/AbilitiesRegistryTest.phpwordpress-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
| 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 ); | ||
| } | ||
| } |
There was a problem hiding this comment.
📐 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
| 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'] ); | ||
| } |
There was a problem hiding this comment.
🎯 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.
…_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
What changed
New
list_binding_sourcestool enumerates registered block bindings sources — what a block'smetadata.bindingsattribute 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) wrapsget_all_registered_block_bindings_sources()behind afunction_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_contextomitted when the source declares none).GET /binding-sourcesroute,check_permissions, no args.src/client.ts:getBindingSources().src/tools/discovery.ts: newlist_binding_sourcestool, no input args,READ_ANNOT.src/agent-guide.ts: new "Block bindings" section — checklist_binding_sourcesbefore wiringmetadata.bindingsto a source.tools.manifest.json(27 → 28 tools) +assets/mcp-server/index.cjs.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-metaandcore/pattern-overridespresent on the test install (PHP + live smoke)function_existsbranch itself can't be flipped live on a 6.5+ test environment — documented in the test)list_binding_sources→client.getBindingSources(), no args) + response passthrough (sources,note)Gate output
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:core/post-metaandcore/pattern-overridesboth 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
list_binding_sourcesto show registered block binding sources (including context usage where supported).