modelcontextprotocol / modelcontextprotocol/typescript-sdk

Bug Report-1: Missing Cancellation Logging Implementation

Open
#999 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

  • #1034 by @KKonstantinov — closed without merging
bug enhancement P2 ready for work
Dominant language
TypeScript
Stars
13.4k
Forks
2.2k
Avg merge
3d 15h
Merged PRs (30d)
4

Description

Summary

The TypeScript SDK violates the MCP specification by not implementing logging for cancellation reasons, which is explicitly required for debugging purposes.

Specification Violation

According to the MCP specification, cancellation notifications should include logging requirements:

Receivers of cancellation notifications SHOULD:
Both parties SHOULD log cancellation reasons for debugging

Current Implementation Issue

Location

File: src/shared/protocol.ts
Functions:

  • Protocol.request() method - cancel function (lines 582-601)
  • Protocol constructor - cancellation notification handler (lines 231-236)
Architecture Context
  • Protocol is a base class inherited by both Client and Server
  • Both sending and receiving cancellation notifications happen in the shared base class
  • The specification requires both parties to log cancellation reasons
Problem

The current implementation lacks logging for cancellation reasons on both sides:

1. Sender Side (cancel function)
const cancel = (reason: unknown) => {
  this._responseHandlers.delete(messageId);
  this._progressHandlers.delete(messageId);
  this._cleanupTimeout(messageId);

  this._transport?.send({
    jsonrpc: "2.0",
    method: "notifications/cancelled",
    params: {
      requestId: messageId,
      reason: String(reason),  // ✅ Reason is sent
    },
  });
  // ❌ Missing: No logging of why the request was cancelled
};
2. Receiver Side (notification handler)
this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
  const controller = this._requestHandlerAbortControllers.get(
    notification.params.requestId,
  );
  controller?.abort(notification.params.reason);
  // ❌ Missing: No logging of received cancellation notification
});

Impact

  • Specification Compliance: Violates explicit MCP requirement for logging cancellation reasons
  • Debugging Difficulty: No visibility into why requests are being cancelled
  • Troubleshooting: Difficult to diagnose cancellation-related issues in production
  • Monitoring: No audit trail for cancellation events

Proposed Fix

1. Sender Side Logging

Add logging in the cancel function:

const cancel = (reason: unknown) => {
  // Log cancellation reason for debugging
  console.log(`[${this.constructor.name}] Cancelling request ${messageId}: ${String(reason)}`);
  
  this._responseHandlers.delete(messageId);
  this._progressHandlers.delete(messageId);
  this._cleanupTimeout(messageId);

  this._transport?.send({
    jsonrpc: "2.0",
    method: "notifications/cancelled",
    params: {
      requestId: messageId,
      reason: String(reason),
    },
  });
};
2. Receiver Side Logging

Add logging in the notification handler:

this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
  // Log received cancellation notification for debugging
  console.log(`[${this.constructor.name}] Received cancellation for request ${notification.params.requestId}: ${notification.params.reason || 'No reason provided'}`);
  
  const controller = this._requestHandlerAbortControllers.get(
    notification.params.requestId,
  );
  controller?.abort(notification.params.reason);
});
3. Alternative: Configurable Logging

Make logging configurable to avoid console spam in production:

constructor(private _options?: ProtocolOptions) {
  // Add logging option
  const enableCancellationLogging = this._options?.enableCancellationLogging ?? true;
  
  this.setNotificationHandler(CancelledNotificationSchema, (notification) => {
    if (enableCancellationLogging) {
      console.log(`[${this.constructor.name}] Received cancellation for request ${notification.params.requestId}: ${notification.params.reason || 'No reason provided'}`);
    }
    // ... rest of handler
  });
}

Testing

The fix should be tested with:

  1. Client cancelling requests (should log cancellation reason)
  2. Server cancelling requests (should log cancellation reason)
  3. Client receiving cancellation notifications (should log received cancellation)
  4. Server receiving cancellation notifications (should log received cancellation)
  5. Different cancellation reasons (timeout, manual abort, error conditions)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading src/shared/protocol.ts, especially Protocol.request()'s cancel function and the cancellation notification handler in the constructor. Check how cancellation is sent and received, then add coverage for client and server cancellation with different reasons. Done means both sides provide cancellation-reason logging without changing cancellation behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.