Skip to content

fix: Tag filtering in /tools endpoint after schema migration to dict format#2588

Merged
crivetimihai merged 1 commit intomainfrom
fix_issue_2329_tag
Jan 31, 2026
Merged

fix: Tag filtering in /tools endpoint after schema migration to dict format#2588
crivetimihai merged 1 commit intomainfrom
fix_issue_2329_tag

Conversation

@rakdutta
Copy link
Copy Markdown
Collaborator

Closes #2329

Fixes tag-based filtering in the /tools endpoint after the migration from List[str] to List[Dict[str, str]].
Introduces a unified tag-filtering helper to correctly handle both legacy string tags and {id, label} tags across SQLite and PostgreSQL.
Resolves failures in both database-backed and in-memory filtering paths.
Adds unit tests to validate tag filtering behavior.
The same tag-filtering functionality is verified for resources, prompts, A2A server, server export, and tag servers.

Note: Testing should be performed using PostgreSQL.

Example for Verify tag-based filtering --

# Expected: returns tool which have local tags
  'http://localhost:4444/tools?include_pagination=false&include_inactive=false&tags=local' \
  -H 'accept: application/json' \
  -H 'Content-Type: application/json'\
 -H "Authorization: Bearer $MCPGATEWAY_BEARER_TOKEN"




@rakdutta rakdutta marked this pull request as ready for review January 30, 2026 14:26
@crivetimihai crivetimihai self-assigned this Jan 31, 2026
Fixes #2329

Updates tag filtering in TagService.get_entities_by_tag() to use the
cross-database compatible json_contains_tag_expr helper instead of the
raw json_extract LIKE query that only worked with string arrays.

Changes:
- Replace func.json_extract(tags, "$").LIKE query with json_contains_tag_expr
  which supports both legacy string tags and new dict-format tags
- Update PostgreSQL implementation to use table_valued() pattern for
  idiomatic SQLAlchemy handling of jsonb_array_elements (elem.c.value)
- Update unit tests to mock database dialect for json_contains_tag_expr
- Improve test mocking to use patch.object context manager
- Fix docstring to reflect new implementation (was "JSON LIKE queries")
- Add comprehensive tests for dict-format tags [{id, label}]
- Add rigorous PostgreSQL SQL compilation tests with regex validation
- Document design decision: DB filters by 'id' only (TagValidator ensures
  id is always present; label is for display only)

The json_contains_tag_expr helper handles both formats:
- Legacy: ["tag1", "tag2"]
- Dict format: [{"id": "tag1", "label": "Tag 1"}, ...]

PostgreSQL implementation uses table_valued() for explicit column reference:
- func.jsonb_array_elements(...).table_valued("value").alias("elem")
- elem.c.value.op("->>")("id") for proper column access

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai
Copy link
Copy Markdown
Member

Review Changes Applied

Rebased on main and squashed 7 commits into 1 clean commit. Made the following improvements based on code review:

PostgreSQL Implementation Fix

  • Changed from literal_column("elem") aliasing to idiomatic SQLAlchemy table_valued() pattern
  • Now uses func.jsonb_array_elements(...).table_valued("value").alias("elem") with elem.c.value.op("->>")("id")
  • This produces explicit elem.value ->> 'id' SQL instead of implicit elem ->> 'id'

Documentation & Tests

  • Fixed docstring in TagService.get_entities_by_tag() (was "JSON LIKE queries", now "json_contains_tag_expr")
  • Added design comments explaining id-only filtering (label is for display, TagValidator ensures id is always present)
  • Added 8 new tests for dict-format tags [{id, label}]
  • Added PostgreSQL SQL compilation tests with regex validation for elem.value pattern
  • Fixed pre-existing lint issues in test file

Verification

  • All 1886 service tests pass
  • Tested PostgreSQL SQL against real database - works correctly
  • Both string tags ["tag"] and dict tags [{"id": "tag", "label": "Tag"}] filter correctly

@crivetimihai crivetimihai merged commit 49304f3 into main Jan 31, 2026
51 checks passed
@crivetimihai crivetimihai deleted the fix_issue_2329_tag branch January 31, 2026 17:02
hughhennelly pushed a commit to hughhennelly/mcp-context-forge that referenced this pull request Feb 8, 2026
…2588)

Fixes IBM#2329

Updates tag filtering in TagService.get_entities_by_tag() to use the
cross-database compatible json_contains_tag_expr helper instead of the
raw json_extract LIKE query that only worked with string arrays.

Changes:
- Replace func.json_extract(tags, "$").LIKE query with json_contains_tag_expr
  which supports both legacy string tags and new dict-format tags
- Update PostgreSQL implementation to use table_valued() pattern for
  idiomatic SQLAlchemy handling of jsonb_array_elements (elem.c.value)
- Update unit tests to mock database dialect for json_contains_tag_expr
- Improve test mocking to use patch.object context manager
- Fix docstring to reflect new implementation (was "JSON LIKE queries")
- Add comprehensive tests for dict-format tags [{id, label}]
- Add rigorous PostgreSQL SQL compilation tests with regex validation
- Document design decision: DB filters by 'id' only (TagValidator ensures
  id is always present; label is for display only)

The json_contains_tag_expr helper handles both formats:
- Legacy: ["tag1", "tag2"]
- Dict format: [{"id": "tag1", "label": "Tag 1"}, ...]

PostgreSQL implementation uses table_valued() for explicit column reference:
- func.jsonb_array_elements(...).table_valued("value").alias("elem")
- elem.c.value.op("->>")("id") for proper column access

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: hughhennnelly <hughhennelly06@gmail.com>
kcostell06 pushed a commit to kcostell06/mcp-context-forge that referenced this pull request Feb 24, 2026
…2588)

Fixes IBM#2329

Updates tag filtering in TagService.get_entities_by_tag() to use the
cross-database compatible json_contains_tag_expr helper instead of the
raw json_extract LIKE query that only worked with string arrays.

Changes:
- Replace func.json_extract(tags, "$").LIKE query with json_contains_tag_expr
  which supports both legacy string tags and new dict-format tags
- Update PostgreSQL implementation to use table_valued() pattern for
  idiomatic SQLAlchemy handling of jsonb_array_elements (elem.c.value)
- Update unit tests to mock database dialect for json_contains_tag_expr
- Improve test mocking to use patch.object context manager
- Fix docstring to reflect new implementation (was "JSON LIKE queries")
- Add comprehensive tests for dict-format tags [{id, label}]
- Add rigorous PostgreSQL SQL compilation tests with regex validation
- Document design decision: DB filters by 'id' only (TagValidator ensures
  id is always present; label is for display only)

The json_contains_tag_expr helper handles both formats:
- Legacy: ["tag1", "tag2"]
- Dict format: [{"id": "tag1", "label": "Tag 1"}, ...]

PostgreSQL implementation uses table_valued() for explicit column reference:
- func.jsonb_array_elements(...).table_valued("value").alias("elem")
- elem.c.value.op("->>")("id") for proper column access

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
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.

[BUG]: Tag filter returns 500 Exception for list tools api

2 participants