Skip to content

fix(mcp): resync /mcp gateway tools/list on connect, reconnect, and tool-sync drift#5047

Open
Shaik-Sirajuddin wants to merge 4 commits into
maximhq:devfrom
Shaik-Sirajuddin:fix/mcp-gateway-tools-sync
Open

fix(mcp): resync /mcp gateway tools/list on connect, reconnect, and tool-sync drift#5047
Shaik-Sirajuddin wants to merge 4 commits into
maximhq:devfrom
Shaik-Sirajuddin:fix/mcp-gateway-tools-sync

Conversation

@Shaik-Sirajuddin

@Shaik-Sirajuddin Shaik-Sirajuddin commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #4998. The /mcp gateway's tools/list served a stale, cached snapshot rebuilt only on admin config mutations (add/update/remove/enable/disable a client). Boot-time client dialing, manual/health-monitor reconnects, and periodic tool-sync drift all mutated a client's live tool state without ever triggering a resync, so tools/list could serve {"tools":[]} indefinitely after a clean restart until an admin toggled a client.

Changes

  • Added a coalesced onToolsUpdated hook on MCPManager (core/mcp/mcp.go), fired from connectToMCPClient (covers boot, manual reconnect, health-monitor reconnect) and performSync (covers periodic tool-sync drift), only on their success paths.
  • Wired the hook through MCPManagerInterface, Bifrost, and the transport's Bootstrap to call SyncAllMCPServers.
  • Bifrost retains the callback and re-applies it to any MCPManager constructed later by a lazy-init path (AddMCPClient, VerifyPerUserOAuthConnection, VerifyHeadersConnection, SetMCPManager), covering processes that start with no MCP configured.
  • Added core/mcp_lazy_hook_verify_test.go covering the lazy-init path.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 589794a9-916c-4c8d-9ce4-1f1700a8c847

📥 Commits

Reviewing files that changed from the base of the PR and between bc4cea4 and ca891b4.

📒 Files selected for processing (5)
  • core/mcp/dispatcherpanic_test.go
  • core/mcp/mcp.go
  • core/mcp/toolsync.go
  • core/mcp/toolsyncnotify_test.go
  • core/mcplazyhookverify_test.go
💤 Files with no reviewable changes (1)
  • core/mcplazyhookverify_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • core/mcp/mcp.go

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Live MCP tool updates now automatically refresh the gateway tool list, keeping available tools in sync after reconnects or tool changes.
    • Tool synchronization now detects real content changes more accurately, reducing unnecessary refreshes.
  • Bug Fixes

    • Fixed a gap where MCP tool updates could be missed during lazy initialization or when using an externally provided manager.
    • Improved reliability so update callbacks continue working even if one invocation fails.

Walkthrough

This PR adds a retained "tools updated" callback mechanism to Bifrost and MCPManager. MCPManager gains a coalescing dispatcher and non-blocking notify path triggered from client connect and diff-gated tool sync flows. Bifrost exposes SetOnMCPToolsUpdated, re-applying it across lazy manager construction paths, and the HTTP server bootstrap wires it to resync gateway tool registries.

Changes

MCP Tools-Updated Hook

Layer / File(s) Summary
MCPManager tools-updated dispatcher
core/mcp/mcp.go, core/mcp/interface.go, core/mcp/dispatcherpanic_test.go
MCPManager adds a mutex-guarded callback, buffered channel, dispatcher goroutine, panic-safe invocation, SetOnToolsUpdated, notifyToolsUpdated, interface declaration, and a panic-recovery test.
Trigger notifications from connect/sync flows
core/mcp/clientmanager.go, core/mcp/toolsync.go, core/mcp/toolsyncnotify_test.go
Client connect calls notifyToolsUpdated(); performSync now uses reflect.DeepEqual to detect actual ToolMap changes and only notifies when content differs, with tests verifying diff-gated behavior.
Bifrost-level callback registration and lazy re-wiring
core/bifrost.go
Adds retained callback fields, SetOnMCPToolsUpdated, and applyMCPToolsUpdatedHook, invoked after Init, AddMCPClient, SetMCPManager, VerifyPerUserOAuthConnection, and VerifyHeadersConnection.
HTTP server wiring and lazy-init test
transports/bifrost-http/server/server.go, core/mcplazyhookverify_test.go
Bootstrap wires SetOnMCPToolsUpdated to trigger SyncAllMCPServers; a test verifies a lazily constructed MCPManager receives the hook after AddMCPClient.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client as MCP Client
  participant ClientManager
  participant MCPManager
  participant Dispatcher as ToolsUpdatedDispatcher
  participant Bifrost
  participant Server as HTTP Server

  Bifrost->>MCPManager: applyMCPToolsUpdatedHook()
  Client->>ClientManager: connect / performSync
  ClientManager->>MCPManager: notifyToolsUpdated() (on connect or diff detected)
  MCPManager->>Dispatcher: signal via toolsUpdatedCh
  Dispatcher->>Bifrost: invoke onMCPToolsUpdated callback
  Bifrost->>Server: SetOnMCPToolsUpdated callback fires
  Server->>Server: SyncAllMCPServers(context.Background())
Loading

Possibly related issues

Possibly related PRs

  • maximhq/bifrost#3389: Both PRs modify the performSync path in core/mcp/toolsync.go, one adding hook-based tool retrieval, the other diff-gating and dispatching notifyToolsUpdated.
  • maximhq/bifrost#3768: Both PRs touch the MCP client add/connect flow through AddMCPClient into MCPManager, though for different purposes.
  • maximhq/bifrost#4316: Both PRs modify connectToMCPClient in core/mcp/clientmanager.go around tool discovery and connection handling.

Suggested reviewers: akshaydeo, danpiths, Pratham-Mishra04

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description has Summary and Changes, but it omits most template sections like type, testing, breaking changes, and checklist. Add the missing template sections, especially Type of change, Affected areas, How to test, Breaking changes, Related issues, Security considerations, and Checklist.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: resyncing /mcp tools/list on client connect, reconnect, and sync drift.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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.

@coderabbitai coderabbitai Bot requested review from akshaydeo and danpiths July 9, 2026 05:37
@greptile-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Confidence Score: 5/5

This looks safe to merge.

  • No blocking issues found in the changed code.

Important Files Changed

Filename Overview
core/bifrost.go Stores and reapplies the MCP tools-updated callback across boot and lazy manager creation paths.
core/mcp/mcp.go Adds the coalesced dispatcher that runs the tools-updated hook safely.
core/mcp/clientmanager.go Triggers the tools-updated notification after successful MCP client connection.
core/mcp/toolsync.go Notifies downstream registry sync only when the refreshed tool map changes.
transports/bifrost-http/server/server.go Registers the MCP gateway resync callback before configured clients are connected.

Reviews (4): Last reviewed commit: "Merge remote-tracking branch 'origin/fix..." | Re-trigger Greptile

…ool-sync drift

The gateway's tools/list served a stale snapshot rebuilt only on admin config
mutations (add/update/remove/enable/disable a client). Boot-time client dialing,
manual/health-monitor reconnects, and periodic tool-sync drift all mutated a
client's live ToolMap without ever triggering a resync, so /mcp could serve
{"tools":[]} indefinitely after a clean restart until an admin toggled a client.

Adds an onToolsUpdated hook on MCPManager, coalesced through a buffered channel
so bursts of concurrent connects collapse into at most one extra resync, fired
from connectToMCPClient and performSync only on their success paths. The
transport wires this to SyncAllMCPServers in Bootstrap, and Bifrost retains the
callback so it's re-applied to any MCPManager constructed later by a lazy-init
path (AddMCPClient, VerifyPerUserOAuthConnection, VerifyHeadersConnection,
SetMCPManager) for processes that start with no MCP configured.

Fixes maximhq#4998
@Shaik-Sirajuddin Shaik-Sirajuddin force-pushed the fix/mcp-gateway-tools-sync branch from f991995 to 3ec80c9 Compare July 9, 2026 05:39

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@core/mcp_lazy_hook_verify_test.go`:
- Line 1: The Go test file name violates the repo naming convention because it
uses underscores before the _test.go suffix. Rename the test file to a
concatenated lowercase form matching the existing symbol/package context in
core/mcp_lazy_hook_verify_test.go, such as mcplazyhookverify_test.go, and ensure
any references in build or test tooling still point to the renamed file.

In `@core/mcp/mcp.go`:
- Around line 236-256: `runToolsUpdatedDispatcher` calls the registered
`onToolsUpdated` hook without any panic protection, so a panic in `fn()` can
crash the whole process. Wrap the `fn()` invocation in
`runToolsUpdatedDispatcher` with a defer/recover guard inside the same
goroutine, and log the recovered panic as a warning while keeping the dispatcher
alive. Use the existing `MCPManager` hook wiring (`onToolsUpdated`,
`onToolsUpdatedMu`, `toolsUpdatedCh`) to locate the call site.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ac562f0a-c699-479f-b10e-fca3b48cf25d

📥 Commits

Reviewing files that changed from the base of the PR and between efa59f5 and f991995.

📒 Files selected for processing (7)
  • core/bifrost.go
  • core/mcp/clientmanager.go
  • core/mcp/interface.go
  • core/mcp/mcp.go
  • core/mcp/toolsync.go
  • core/mcp_lazy_hook_verify_test.go
  • transports/bifrost-http/server/server.go

@@ -0,0 +1,125 @@
package bifrost

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Filename uses underscores beyond the permitted _test.go suffix.

Per repo convention, Go filenames should have no underscores except the _test.go suffix, with multi-word names concatenated (e.g. pluginpipeline_test.go, not plugin_pipeline_test.go). mcp_lazy_hook_verify_test.go should be mcplazyhookverify_test.go.

As per coding guidelines: "Go filenames use no underscores except for _test.go suffix; use concatenated lowercase words (e.g., pluginpipeline.go, not plugin_pipeline.go)."

🤖 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 `@core/mcp_lazy_hook_verify_test.go` at line 1, The Go test file name violates
the repo naming convention because it uses underscores before the _test.go
suffix. Rename the test file to a concatenated lowercase form matching the
existing symbol/package context in core/mcp_lazy_hook_verify_test.go, such as
mcplazyhookverify_test.go, and ensure any references in build or test tooling
still point to the renamed file.

Source: Coding guidelines

Comment thread core/mcp/mcp.go
@Shaik-Sirajuddin Shaik-Sirajuddin marked this pull request as draft July 9, 2026 05:53
…anics

Addresses two follow-up issues found after the initial fix:

- performSync now only calls notifyToolsUpdated when the synced tool set
  actually changed (deep comparison, not just count). Notifying on every
  tick regardless invalidated the entire per-VK gateway-server cache on
  every tool-sync interval across every configured client even when
  nothing changed, eroding the lazy per-VK caching that exists to avoid
  O(virtual keys) work at scale.
- runToolsUpdatedDispatcher now recovers a panic in the registered hook
  instead of crashing the process; since the dispatcher goroutine never
  restarts, an unrecovered panic would silently stop all future gateway
  resyncs for the rest of the process lifetime.
- Renamed new test files to match repo convention (no underscores beyond
  the _test.go suffix).
@Shaik-Sirajuddin Shaik-Sirajuddin marked this pull request as ready for review July 9, 2026 06:07
@coderabbitai coderabbitai Bot requested a review from Pratham-Mishra04 July 9, 2026 06:08
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]: Insufficient fix for #4314, /mcp gateway still serves 0 tools after restart and reconnect because the tool registry is never resynced

1 participant