Skip to content

Fix MCP get-items returning zero results due to empty filter values#349

Merged
superdav42 merged 1 commit intomainfrom
fix/mcp-empty-filter-values
Mar 2, 2026
Merged

Fix MCP get-items returning zero results due to empty filter values#349
superdav42 merged 1 commit intomainfrom
fix/mcp-empty-filter-values

Conversation

@superdav42
Copy link
Collaborator

@superdav42 superdav42 commented Mar 1, 2026

Summary

  • LLMs populate every schema field with default values ("" for strings, false for booleans) even when no filter is intended
  • BerlinDB interprets these literally as WHERE clauses (e.g. WHERE type = '' or WHERE recurring = 0), returning zero rows
  • Strip empty strings and false booleans from $args in mcp_get_items() before passing them to query()
  • Affects all models using the MCP_Abilities trait (products, memberships, customers, sites, payments, etc.)

Test plan

  • Ask the AI Agent "how many products do we have?" — should return all active products instead of 0
  • Ask the AI Agent to list memberships/customers — verify same fix applies
  • Verify intentional filters still work (e.g. "list all plan-type products" should filter by type=plan)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved MCP abilities registration to automatically work whenever the registration method is available, removing unnecessary checks.
    • Enhanced query filtering to properly exclude empty and false values from input arguments, ensuring only valid filters are applied while maintaining existing pagination and counting behavior.

LLMs populate every schema field with default values ("" for strings,
false for booleans) even when no filter is intended. BerlinDB interprets
these literally as WHERE clauses (e.g. WHERE type = '' or WHERE
recurring = 0), which matches nothing or nearly nothing.

Strip empty strings and false booleans from args before passing them to
the query. This affects all models using the MCP_Abilities trait
(products, memberships, customers, etc.).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 1, 2026

📝 Walkthrough

Walkthrough

Modified MCP abilities trait to remove an early MCP-enabled check in the registration function, allowing processing when wp_register_ability exists. Also updated item retrieval to pre-filter arguments, removing empty strings and false values before query execution while maintaining existing pagination behavior.

Changes

Cohort / File(s) Summary
MCP Abilities Trait
inc/apis/trait-mcp-abilities.php
Removed conditional early exit in enable_mcp_abilities to permit registration when wp_register_ability is available. Added argument sanitization in mcp_get_items to filter out empty and false values before query execution.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 With checks removed and filters bright,
The MCP abilities take their flight,
Empty values swept away with care,
Cleaner queries fill the air! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main fix: preventing MCP get-items from returning zero results by filtering out empty values.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/mcp-empty-filter-values

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link

github-actions bot commented Mar 1, 2026

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@inc/apis/trait-mcp-abilities.php`:
- Around line 751-760: The current array_filter callback removes falsy false
values and so discards intentional boolean filters; update the callback used on
$args (the anonymous function passed to array_filter) to only remove empty
strings and nulls while preserving boolean false (e.g., return !($value === ''
|| $value === null)); ensure you do not use loose comparisons (==) so false
remains intact, and consider adjusting upstream schema defaults for boolean
filter properties to prevent LLMs from auto-populating false in the first place.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb0cfe8 and d76da7d.

📒 Files selected for processing (1)
  • inc/apis/trait-mcp-abilities.php

Comment on lines +751 to +760
// LLMs fill in every schema field with default-ish values like ""
// or false. BerlinDB interprets these literally (WHERE type = '' or
// WHERE recurring = 0), returning zero rows. Strip them out so only
// intentional filters reach the query.
$args = array_filter(
$args,
function ($value) {
return '' !== $value && false !== $value;
}
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Stripping false may silently discard intentional boolean filters.

The current filter removes all false values, but users may legitimately want to query for items where a boolean field is false (e.g., active = false to list inactive products, or recurring = false to find one-time purchases). This fix would make those queries impossible.

Consider one of these approaches:

  1. Track which fields were explicitly provided by the caller vs. auto-populated defaults
  2. Use a sentinel value (e.g., null) for "not specified" and only strip those
  3. Require the LLM/caller to omit fields entirely rather than sending defaults (adjust schema to not have defaults for filter fields)

Additionally, null values pass through this filter (null !== false is true) and may also cause unexpected query behavior depending on how BerlinDB handles them.

Proposed fix to also filter null while preserving intentional false

One approach is to filter only truly "empty" values while keeping explicit booleans. However, this requires distinguishing intent, which may need upstream schema changes:

 		$args = array_filter(
 			$args,
 			function ($value) {
-				return '' !== $value && false !== $value;
+				// Strip empty strings and null; keep false for intentional boolean filters
+				return '' !== $value && null !== $value;
 			}
 		);

Note: This alone doesn't fully solve the LLM default problem for booleans. A more robust solution would be to remove default values from boolean filter properties in the schema (lines 648-705) so LLMs don't auto-fill them.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// LLMs fill in every schema field with default-ish values like ""
// or false. BerlinDB interprets these literally (WHERE type = '' or
// WHERE recurring = 0), returning zero rows. Strip them out so only
// intentional filters reach the query.
$args = array_filter(
$args,
function ($value) {
return '' !== $value && false !== $value;
}
);
// LLMs fill in every schema field with default-ish values like ""
// or false. BerlinDB interprets these literally (WHERE type = '' or
// WHERE recurring = 0), returning zero rows. Strip them out so only
// intentional filters reach the query.
$args = array_filter(
$args,
function ($value) {
// Strip empty strings and null; keep false for intentional boolean filters
return '' !== $value && null !== $value;
}
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@inc/apis/trait-mcp-abilities.php` around lines 751 - 760, The current
array_filter callback removes falsy false values and so discards intentional
boolean filters; update the callback used on $args (the anonymous function
passed to array_filter) to only remove empty strings and nulls while preserving
boolean false (e.g., return !($value === '' || $value === null)); ensure you do
not use loose comparisons (==) so false remains intact, and consider adjusting
upstream schema defaults for boolean filter properties to prevent LLMs from
auto-populating false in the first place.

@superdav42 superdav42 merged commit 3b086cb into main Mar 2, 2026
9 checks passed
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