-
Notifications
You must be signed in to change notification settings - Fork 14.5k
fix(mcp-client): prevent eager tool wipe on network timeout #27383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
50f36a2
17b222a
fae56f3
7f4055d
520363f
d2d3f65
47d23e9
394fbbf
7c7b964
59e74d0
9dab832
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1244,9 +1244,15 @@ describe('mcp-client', () => { | |
| await client.disconnect(); | ||
|
|
||
| expect(mockedClient.close).toHaveBeenCalledOnce(); | ||
| expect(mockedToolRegistry.removeMcpToolsByServer).toHaveBeenCalledOnce(); | ||
| expect(mockedPromptRegistry.removePromptsByServer).toHaveBeenCalledOnce(); | ||
| expect(resourceRegistry.removeResourcesByServer).toHaveBeenCalledOnce(); | ||
| expect(mockedToolRegistry.removeMcpToolsByServer).toHaveBeenCalledWith( | ||
| 'test-server', | ||
| ); | ||
| expect(mockedPromptRegistry.removePromptsByServer).toHaveBeenCalledWith( | ||
| 'test-server', | ||
| ); | ||
| expect(resourceRegistry.removeResourcesByServer).toHaveBeenCalledWith( | ||
| 'test-server', | ||
| ); | ||
| }); | ||
| }); | ||
|
|
||
|
|
@@ -1570,8 +1576,8 @@ describe('mcp-client', () => { | |
| // Trigger notification - should fail internally but catch the error | ||
| await notificationCallback(); | ||
|
|
||
| // Should try to remove tools | ||
| expect(mockedToolRegistry.removeMcpToolsByServer).toHaveBeenCalled(); | ||
| // Should NOT try to remove tools because discovery failed (atomic refresh) | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following is an explanation about the fix and changes in to the testing: ┌───────────────────────────────────┬─────────────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Test Name │ Scenario Tested │ How the PR Change Validates It │
├───────────────────────────────────┼─────────────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ "should handle errors during tool │ A background refresh is triggered, but the network call │ It mocks listTools to reject with an Error. It then asserts that removeMcpToolsByServer is NOT called. │
│ refresh gracefully" │ (listTools) fails. │ This confirms the throw successfully aborted the wipe. │
└───────────────────────────────────┴─────────────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
||
| expect(mockedToolRegistry.removeMcpToolsByServer).not.toHaveBeenCalled(); | ||
|
|
||
| // Should NOT emit success feedback | ||
| expect(coreEvents.emitFeedback).not.toHaveBeenCalledWith( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1404,6 +1404,7 @@ export async function discoverTools( | |
| error, | ||
| mcpServerName, | ||
| ); | ||
| throw error; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following is an explanation how the "throw" is fixing the issue: Scenario: The user asks a complex question. While the LLM is "thinking" (which takes 30 seconds), the MCP server connection drops, triggering a background refresh. ┌──────┬──────────────────────────────────────┬───────────────────────────────────────┬────────────────────────────────────────────────────────────────────┐
│ Step │ Action │ State BEFORE Fix (Bug) │ State AFTER Fix (PR Solution) │
├──────┼──────────────────────────────────────┼───────────────────────────────────────┼────────────────────────────────────────────────────────────────────┤
│ 1 │ LLM starts generating response. │ Tool Registry has [Tool_A, Tool_B]. │ Tool Registry has [Tool_A, Tool_B]. │
│ 2 │ Background refreshTools starts. │ Enters try block. │ Enters try block. │
│ 3 │ discoverTools is called. │ Fails due to connection drop. │ Fails due to connection drop. │
│ 4 │ discoverTools handles error. │ Logs error, returns []. │ Logs error, throws error. │
│ 5 │ refreshTools reacts. │ Receives []. Continues try block. │ Catches error. Jumps to catch block. │
│ 6 │ Registry Update. │ Executes removeMcpToolsByServer. │ Skips removeMcpToolsByServer. │
│ 7 │ Registry State. │ Registry is now EMPTY. │ Registry still has [Tool_A, Tool_B]. │
│ 8 │ LLM finishes thinking, calls Tool_A. │ Scheduler looks for Tool_A. Fails. │ Scheduler looks for Tool_A. Finds it. │
│ 9 │ Final Outcome │ ❌ CLI crashes with "Tool not found". │ ✅ Tool executes (or fails gracefully with "Server Disconnected"). │
└──────┴──────────────────────────────────────┴───────────────────────────────────────┴────────────────────────────────────────────────────────────────────┘
|
||
| } | ||
| return []; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The following is an explanation about the fix and changes into the testing: