Skip to content

fix(visibility): prevent auto-refresh from overriding tool/prompt/resource visibility#3574

Merged
crivetimihai merged 5 commits intomainfrom
3530_fix_visibility_change_auto_refresh
Mar 11, 2026
Merged

fix(visibility): prevent auto-refresh from overriding tool/prompt/resource visibility#3574
crivetimihai merged 5 commits intomainfrom
3530_fix_visibility_change_auto_refresh

Conversation

@kevalmahajan
Copy link
Copy Markdown
Member

@kevalmahajan kevalmahajan commented Mar 10, 2026

🐛 Bug-fix PR

Closes #3530

📌 Summary

Fixed a bug where the AUTO_REFRESH_SERVERS=true configuration overrides the granular visibility settings of individual tools, resources, and prompts. Previously, during a server auto-refresh, any explicitly configured "Private" or "Team" items would automatically be changed to match the parent Gateway's visibility (e.g., "Public"). This fix ensures that background sync operations preserve existing visibility configurations while still allowing manual UI/API updates to propagate visibility changes correctly.

🔁 Reproduction Steps

  1. Create and configure an MCP Gateway with "Public" visibility.
  2. Allow the Gateway to perform its initial sync so that its tools default to "Public".
  3. Manually update one of the synced tools to have "Private" visibility.
  4. Trigger a background auto-refresh for the Gateway (e.g., via AUTO_REFRESH_SERVERS=true or a health check).
  5. Observed Bug: The tool's visibility is changed back to "Public".
  6. Expected Behavior: The tool remains "Private".

🐞 Root Cause

The _update_or_create_tools, _update_or_create_resources, and _update_or_create_prompts helper methods in mcpgateway/services/gateway_service.py contained logic that unconditionally applied existing_item.visibility = gateway.visibility during the synchronization process. The methods did not differentiate between an automatic background refresh and a manual update triggered by a user.

💡 Fix Description

The _update_or_create_tools, _update_or_create_resources, and _update_or_create_prompts helper methods in mcpgateway/services/gateway_service.py contained logic that unconditionally applied existing_item.visibility = gateway.visibility during the synchronization process. The methods did not differentiate between an automatic background refresh and a manual update triggered by a user.

💡 Fix Description

Updated the synchronization logic across tools, resources, and prompts to conditionally evaluate visibility changes based on the operation's context.

  • Introduced a should_update_visibility = created_via == "update" condition.
  • The item's visibility attribute is now explicitly excluded from the fields_to_update conditions and field assignment blocks unless the sync is triggered by a manual update ("update").
  • Added comprehensive unit tests test_update_visibility_logic and updated removal scenarios) in test_gateway_service_extended.py to assert that visibility correctly inherits during manual updates but is preserved during auto_refresh, health_check, and rediscovery contexts.

🧪 Verification

Check Command Status
Lint suite make lint
Unit tests make test
Coverage ≥ 80 % make coverage
Manual regression no longer fails steps / screenshots

📐 MCP Compliance (if relevant)

  • Matches current MCP spec
  • No breaking change to MCP clients

✅ Checklist

  • Code formatted (make black isort pre-commit)
  • No secrets/credentials committed

@kevalmahajan kevalmahajan added the bug Something isn't working label Mar 10, 2026
@kevalmahajan kevalmahajan added this to the Release 1.0.0 milestone Mar 10, 2026
@crivetimihai crivetimihai self-assigned this Mar 11, 2026
kevalmahajan and others added 5 commits March 11, 2026 07:21
Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>
Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…coded 'public'

_create_db_tool() hardcoded visibility="public" for all newly discovered
tools, while resources and prompts correctly used gateway.visibility.
This caused new tools on team-scoped or private gateways to be created
with public visibility, breaking team isolation.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
…ed_via check

The previous check `should_update_visibility = created_via == "update"` was
too broad: any gateway edit (e.g. description change) would trigger
visibility propagation to all linked tools/resources/prompts, overwriting
per-item customizations.

Replace with an explicit `update_visibility: bool` parameter on the three
sync helpers, set to True only when the user actually changed the gateway's
visibility in the request (`gateway_update.visibility is not None`).  This
aligns the helper-level gate with the direct propagation logic at lines
1902-1912 which already checks the same condition.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
@crivetimihai crivetimihai force-pushed the 3530_fix_visibility_change_auto_refresh branch from b59cf9a to 20dee56 Compare March 11, 2026 08:20
@crivetimihai
Copy link
Copy Markdown
Member

Review & Changes

Rebased onto main (clean, no conflicts) and reviewed the implementation. The core fix — preserving per-item visibility during auto-refresh — is correct and well-targeted. I've added three commits on top:

1. Formatting cleanup (702b7ce)

Trailing whitespace and extra blank line at EOF flagged by black.

2. New tools inherit gateway visibility (d357598)

_create_db_tool() hardcoded visibility="public" for all newly discovered tools, while resources and prompts correctly used gateway.visibility. This broke team isolation for new tools on non-public gateways. Changed to visibility=gateway.visibility with test.

3. Explicit update_visibility flag (20dee56)

The original should_update_visibility = created_via == "update" was too broad: any gateway edit (e.g., changing only the description) would overwrite custom per-item visibility because the sync helpers always run with created_via="update". The direct propagation at lines 1902–1912 already correctly gates on gateway_update.visibility is not None, but the helpers didn't match.

Replaced with an explicit update_visibility: bool = False parameter on all three sync helpers, set to True only when the user actually changed the gateway's visibility in the request. Added a dedicated test (Test 3) verifying that update_visibility=False preserves custom visibility even during an "update" context.

Verified against live deployment (3-instance + PostgreSQL + Redis):

  • Manual refresh preserves per-item visibility
  • Explicit gateway visibility change propagates to all linked items
  • Deactivate/reactivate cycle preserves visibility
  • Token scoping correctly hides private/team items from public-only tokens

All 4958 unit tests pass, formatting clean.

Copy link
Copy Markdown
Member

@crivetimihai crivetimihai left a comment

Choose a reason for hiding this comment

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

Approved. The core fix is correct and I've added three commits addressing a pre-existing bug (_create_db_tool hardcoding visibility), a correctness issue (unrelated gateway edits overwriting per-item visibility), and formatting. All verified against live deployment and 4958 unit tests pass.

Copy link
Copy Markdown
Member

@crivetimihai crivetimihai left a comment

Choose a reason for hiding this comment

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

Approved. The core fix is correct and I've added three commits addressing a pre-existing bug (_create_db_tool hardcoding visibility), a correctness issue (unrelated gateway edits overwriting per-item visibility), and formatting. All verified against live deployment and 4958 unit tests pass.

@crivetimihai crivetimihai merged commit a02ac5e into main Mar 11, 2026
39 checks passed
@crivetimihai crivetimihai deleted the 3530_fix_visibility_change_auto_refresh branch March 11, 2026 08:28
MohanLaksh pushed a commit that referenced this pull request Mar 12, 2026
…ource visibility (#3574)

* restrict visibility change with auto refresh

Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>

* linting

Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>

* fix: formatting cleanup in test_gateway_service_extended.py

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(visibility): new tools inherit gateway visibility instead of hardcoded 'public'

_create_db_tool() hardcoded visibility="public" for all newly discovered
tools, while resources and prompts correctly used gateway.visibility.
This caused new tools on team-scoped or private gateways to be created
with public visibility, breaking team isolation.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(visibility): use explicit update_visibility flag instead of created_via check

The previous check `should_update_visibility = created_via == "update"` was
too broad: any gateway edit (e.g. description change) would trigger
visibility propagation to all linked tools/resources/prompts, overwriting
per-item customizations.

Replace with an explicit `update_visibility: bool` parameter on the three
sync helpers, set to True only when the user actually changed the gateway's
visibility in the request (`gateway_update.visibility is not None`).  This
aligns the helper-level gate with the direct propagation logic at lines
1902-1912 which already checks the same condition.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Yosiefeyob pushed a commit that referenced this pull request Mar 13, 2026
…ource visibility (#3574)

* restrict visibility change with auto refresh

Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>

* linting

Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>

* fix: formatting cleanup in test_gateway_service_extended.py

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(visibility): new tools inherit gateway visibility instead of hardcoded 'public'

_create_db_tool() hardcoded visibility="public" for all newly discovered
tools, while resources and prompts correctly used gateway.visibility.
This caused new tools on team-scoped or private gateways to be created
with public visibility, breaking team isolation.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

* fix(visibility): use explicit update_visibility flag instead of created_via check

The previous check `should_update_visibility = created_via == "update"` was
too broad: any gateway edit (e.g. description change) would trigger
visibility propagation to all linked tools/resources/prompts, overwriting
per-item customizations.

Replace with an explicit `update_visibility: bool` parameter on the three
sync helpers, set to True only when the user actually changed the gateway's
visibility in the request (`gateway_update.visibility is not None`).  This
aligns the helper-level gate with the direct propagation logic at lines
1902-1912 which already checks the same condition.

Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>

---------

Signed-off-by: Keval Mahajan <mahajankeval23@gmail.com>
Signed-off-by: Mihai Criveti <crivetimihai@gmail.com>
Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
Signed-off-by: Yosief Eyob <yosiefogbazion@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: AUTO_REFRESH_SERVERS Changes Tool Visibility From Private to Public

2 participants