Skip to content

Fix: Gateway Tags Serialization Bug & Transport Reset Issue#2650

Merged
crivetimihai merged 1 commit intomainfrom
issue_2563_tag_type_mismatch
Feb 6, 2026
Merged

Fix: Gateway Tags Serialization Bug & Transport Reset Issue#2650
crivetimihai merged 1 commit intomainfrom
issue_2563_tag_type_mismatch

Conversation

@rakdutta
Copy link
Copy Markdown
Collaborator

@rakdutta rakdutta commented Feb 2, 2026

Closes #2563

This PR primarily fixes Issue #2563, where Gateway tags were returned as an empty list despite being present in the database.
During unit testing for this fix, an additional but related issue was discovered in the Gateway update flow, which is also addressed here.


Primary Issue (#2563): Gateway Tags Returned as Empty List

Problem

Gateway APIs (GET / PUT / PATCH) returned tags: [] even when valid tag data existed in the PostgreSQL JSON column.

Root Causes

  1. Type annotation mismatch
    validate_tags_field() was annotated as returning List[str] but actually returned List[Dict[str, str]], causing Pydantic serialization/coercion issues.

  2. Dict input destruction during validation
    TagValidator.validate_list() stringified dict inputs (e.g. {"id": "finance", "label": "Finance"}), which then failed validation and were filtered out.

  3. Missing legacy tag normalization
    _prepare_gateway_for_read() did not convert legacy string tags to dict format before validation.

Fixes Implemented

mcpgateway/validation/tags.py

  • Corrected validate_tags_field() return type to List[Dict[str, str]]

  • Added passthrough logic for already-formatted tag dictionaries:

    if isinstance(tags[0], dict):
        return [t for t in tags if isinstance(t, dict) and "id" in t and "label" in t]

mcpgateway/schemas.py

  • Updated GatewayCreate.tags and GatewayUpdate.tags to accept both legacy and new formats:

    tags: Optional[List[Union[str, Dict[str, str]]]] = Field(...)
  • Aligned validator return type annotations with actual return values

mcpgateway/services/gateway_service.py

  • Enhanced _prepare_gateway_for_read() to normalize legacy string tags into dict format prior to validation

Result

Gateway tags now serialize and deserialize correctly across all API endpoints, preserving both id and label fields from the database.


Additional Issue Found During Unit Testing: Transport Field Reset

Problem

While validating the tags fix via unit tests, it was observed that updating a gateway without explicitly providing transport caused the field to reset to "SSE" instead of preserving the existing value (e.g. "STREAMABLEHTTP").

This behavior occurred only via the API; the Admin UI was unaffected.

Root Cause

In GatewayUpdate schema:

transport: str = "SSE"

This caused omitted fields in PUT / PATCH requests to overwrite existing values, which violates REST API semantics.

Fix Implemented

  • Updated GatewayUpdate.transport to default to None:

    transport: Optional[str] = Field(None, ...)
  • Ensures existing values are preserved unless explicitly provided in the request


Testing

Verified via curl:

# Before fix:
# - transport reset to SSE
curl -X PUT \
  'http://localhost:4444/gateways/{id}' \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"name":"updated-name"}'

After the fix:

  • Tags are preserved and correctly returned
  • transport remains unchanged unless explicitly passed

@rakdutta rakdutta changed the title Issue 2563 tag type mismatch Fix: Gateway Tags Serialization Bug & Transport Reset Issue Feb 2, 2026
@rakdutta rakdutta marked this pull request as ready for review February 2, 2026 14:04
@crivetimihai crivetimihai added this to the Release 1.0.0-RC1 milestone Feb 3, 2026
@crivetimihai
Copy link
Copy Markdown
Member

Clean fix for both the tags serialization and transport reset issues. The dict passthrough in validate_list(), the _prepare_gateway_for_read() addition to get_first_gateway_by_url, and the nullable transport default are all correct. CI is all green.

LGTM — ready to merge.

@rakdutta rakdutta force-pushed the issue_2563_tag_type_mismatch branch from adb5d59 to 55e56f2 Compare February 4, 2026 05:07
@rakdutta
Copy link
Copy Markdown
Collaborator Author

rakdutta commented Feb 4, 2026

@crivetimihai, I have resolved the merge conflicts and rebased the PR.

@crivetimihai crivetimihai self-assigned this Feb 4, 2026
@rakdutta rakdutta force-pushed the issue_2563_tag_type_mismatch branch from 55e56f2 to 6124751 Compare February 6, 2026 05:18
Closes #2563

This commit fixes two issues:

1. Gateway Tags Returned as Empty List (#2563):
   - Fixed type annotation mismatch in validate_tags_field() to correctly
     return List[Dict[str, str]] instead of List[str]
   - Added passthrough logic for already-formatted tag dictionaries in
     TagValidator.validate_list()
   - Updated GatewayCreate.tags and GatewayUpdate.tags to accept both
     legacy string format and new dict format
   - Fixed parenthesis placement in get_gateway_by_url() to correctly
     call masked() on GatewayRead instead of DbGateway

2. Transport Field Reset During Gateway Update:
   - Changed GatewayUpdate.transport from default="SSE" to None to
     prevent overwriting existing values when field is omitted in
     PUT/PATCH requests

Co-authored-by: rakdutta <rakhibiswas@yahoo.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai crivetimihai force-pushed the issue_2563_tag_type_mismatch branch from 6124751 to c0bea99 Compare February 6, 2026 07:21
@crivetimihai crivetimihai merged commit 278a46d into main Feb 6, 2026
51 checks passed
@crivetimihai crivetimihai deleted the issue_2563_tag_type_mismatch branch February 6, 2026 07:27
kcostell06 pushed a commit to kcostell06/mcp-context-forge that referenced this pull request Feb 24, 2026
Closes IBM#2563

This commit fixes two issues:

1. Gateway Tags Returned as Empty List (IBM#2563):
   - Fixed type annotation mismatch in validate_tags_field() to correctly
     return List[Dict[str, str]] instead of List[str]
   - Added passthrough logic for already-formatted tag dictionaries in
     TagValidator.validate_list()
   - Updated GatewayCreate.tags and GatewayUpdate.tags to accept both
     legacy string format and new dict format
   - Fixed parenthesis placement in get_gateway_by_url() to correctly
     call masked() on GatewayRead instead of DbGateway

2. Transport Field Reset During Gateway Update:
   - Changed GatewayUpdate.transport from default="SSE" to None to
     prevent overwriting existing values when field is omitted in
     PUT/PATCH requests

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]: Gateway tags return empty due to type mismatch between schema and validation layer

2 participants