Skip to content

Commit 6da1da1

Browse files
kiranmagic7Kiran Magic
authored andcommitted
fix(core): preserve related request id zero for debounce
1 parent 542d5c9 commit 6da1da1

3 files changed

Lines changed: 22 additions & 1 deletion

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@modelcontextprotocol/core': patch
3+
---
4+
5+
Preserve `relatedRequestId: 0` when deciding whether notifications can be debounced. Request id `0` is valid, so request-associated notifications with that id now bypass debounce like other related notifications.

packages/core/src/shared/protocol.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -832,7 +832,8 @@ export abstract class Protocol<ContextT extends BaseContext> {
832832
const debouncedMethods = this._options?.debouncedNotificationMethods ?? [];
833833
// A notification can only be debounced if it's in the list AND it's "simple"
834834
// (i.e., has no parameters and no related request ID that could be lost).
835-
const canDebounce = debouncedMethods.includes(notification.method) && !notification.params && !options?.relatedRequestId;
835+
const canDebounce =
836+
debouncedMethods.includes(notification.method) && !notification.params && options?.relatedRequestId === undefined;
836837

837838
if (canDebounce) {
838839
// If a notification of this type is already scheduled, do nothing.

packages/core/test/shared/protocol.test.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,21 @@ describe('protocol tests', () => {
654654
expect(sendSpy).toHaveBeenCalledWith(expect.any(Object), { relatedRequestId: 'req-2' });
655655
});
656656

657+
it('should NOT debounce a notification that has relatedRequestId 0', async () => {
658+
// ARRANGE
659+
protocol = new TestProtocolImpl({ debouncedNotificationMethods: ['test/debounced_with_options'] });
660+
await protocol.connect(transport);
661+
662+
// ACT
663+
const firstNotification = protocol.notification({ method: 'test/debounced_with_options' }, { relatedRequestId: 0 });
664+
const secondNotification = protocol.notification({ method: 'test/debounced_with_options' }, { relatedRequestId: 0 });
665+
await Promise.all([firstNotification, secondNotification]);
666+
667+
// ASSERT
668+
expect(sendSpy).toHaveBeenCalledTimes(2);
669+
expect(sendSpy).toHaveBeenCalledWith(expect.any(Object), { relatedRequestId: 0 });
670+
});
671+
657672
it('should clear pending debounced notifications on connection close', async () => {
658673
// ARRANGE
659674
protocol = new TestProtocolImpl({ debouncedNotificationMethods: ['test/debounced'] });

0 commit comments

Comments
 (0)