ssePollingClient.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /**
  2. * SSE Polling Example Client (SEP-1699)
  3. *
  4. * This example demonstrates client-side behavior during server-initiated
  5. * SSE stream disconnection and automatic reconnection.
  6. *
  7. * Key features demonstrated:
  8. * - Automatic reconnection when server closes SSE stream
  9. * - Event replay via Last-Event-ID header
  10. * - Resumption token tracking via onresumptiontoken callback
  11. *
  12. * Run with: npx tsx src/examples/client/ssePollingClient.ts
  13. * Requires: ssePollingExample.ts server running on port 3001
  14. */
  15. import { Client } from '../../client/index.js';
  16. import { StreamableHTTPClientTransport } from '../../client/streamableHttp.js';
  17. import { CallToolResultSchema, LoggingMessageNotificationSchema } from '../../types.js';
  18. const SERVER_URL = 'http://localhost:3001/mcp';
  19. async function main() {
  20. console.log('SSE Polling Example Client');
  21. console.log('==========================');
  22. console.log(`Connecting to ${SERVER_URL}...`);
  23. console.log('');
  24. // Create transport with reconnection options
  25. const transport = new StreamableHTTPClientTransport(new URL(SERVER_URL), {
  26. // Use default reconnection options - SDK handles automatic reconnection
  27. });
  28. // Track the last event ID for debugging
  29. let lastEventId;
  30. // Set up transport error handler to observe disconnections
  31. // Filter out expected errors from SSE reconnection
  32. transport.onerror = error => {
  33. // Skip abort errors during intentional close
  34. if (error.message.includes('AbortError'))
  35. return;
  36. // Show SSE disconnect (expected when server closes stream)
  37. if (error.message.includes('Unexpected end of JSON')) {
  38. console.log('[Transport] SSE stream disconnected - client will auto-reconnect');
  39. return;
  40. }
  41. console.log(`[Transport] Error: ${error.message}`);
  42. };
  43. // Set up transport close handler
  44. transport.onclose = () => {
  45. console.log('[Transport] Connection closed');
  46. };
  47. // Create and connect client
  48. const client = new Client({
  49. name: 'sse-polling-client',
  50. version: '1.0.0'
  51. });
  52. // Set up notification handler to receive progress updates
  53. client.setNotificationHandler(LoggingMessageNotificationSchema, notification => {
  54. const data = notification.params.data;
  55. console.log(`[Notification] ${data}`);
  56. });
  57. try {
  58. await client.connect(transport);
  59. console.log('[Client] Connected successfully');
  60. console.log('');
  61. // Call the long-task tool
  62. console.log('[Client] Calling long-task tool...');
  63. console.log('[Client] Server will disconnect mid-task to demonstrate polling');
  64. console.log('');
  65. const result = await client.request({
  66. method: 'tools/call',
  67. params: {
  68. name: 'long-task',
  69. arguments: {}
  70. }
  71. }, CallToolResultSchema, {
  72. // Track resumption tokens for debugging
  73. onresumptiontoken: token => {
  74. lastEventId = token;
  75. console.log(`[Event ID] ${token}`);
  76. }
  77. });
  78. console.log('');
  79. console.log('[Client] Tool completed!');
  80. console.log(`[Result] ${JSON.stringify(result.content, null, 2)}`);
  81. console.log('');
  82. console.log(`[Debug] Final event ID: ${lastEventId}`);
  83. }
  84. catch (error) {
  85. console.error('[Error]', error);
  86. }
  87. finally {
  88. await transport.close();
  89. console.log('[Client] Disconnected');
  90. }
  91. }
  92. main().catch(console.error);
  93. //# sourceMappingURL=ssePollingClient.js.map