streamableHttpWithSseFallbackClient.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const index_js_1 = require("../../client/index.js");
  4. const streamableHttp_js_1 = require("../../client/streamableHttp.js");
  5. const sse_js_1 = require("../../client/sse.js");
  6. const types_js_1 = require("../../types.js");
  7. /**
  8. * Simplified Backwards Compatible MCP Client
  9. *
  10. * This client demonstrates backward compatibility with both:
  11. * 1. Modern servers using Streamable HTTP transport (protocol version 2025-03-26)
  12. * 2. Older servers using HTTP+SSE transport (protocol version 2024-11-05)
  13. *
  14. * Following the MCP specification for backwards compatibility:
  15. * - Attempts to POST an initialize request to the server URL first (modern transport)
  16. * - If that fails with 4xx status, falls back to GET request for SSE stream (older transport)
  17. */
  18. // Command line args processing
  19. const args = process.argv.slice(2);
  20. const serverUrl = args[0] || 'http://localhost:3000/mcp';
  21. async function main() {
  22. console.log('MCP Backwards Compatible Client');
  23. console.log('===============================');
  24. console.log(`Connecting to server at: ${serverUrl}`);
  25. let client;
  26. let transport;
  27. try {
  28. // Try connecting with automatic transport detection
  29. const connection = await connectWithBackwardsCompatibility(serverUrl);
  30. client = connection.client;
  31. transport = connection.transport;
  32. // Set up notification handler
  33. client.setNotificationHandler(types_js_1.LoggingMessageNotificationSchema, notification => {
  34. console.log(`Notification: ${notification.params.level} - ${notification.params.data}`);
  35. });
  36. // DEMO WORKFLOW:
  37. // 1. List available tools
  38. console.log('\n=== Listing Available Tools ===');
  39. await listTools(client);
  40. // 2. Call the notification tool
  41. console.log('\n=== Starting Notification Stream ===');
  42. await startNotificationTool(client);
  43. // 3. Wait for all notifications (5 seconds)
  44. console.log('\n=== Waiting for all notifications ===');
  45. await new Promise(resolve => setTimeout(resolve, 5000));
  46. // 4. Disconnect
  47. console.log('\n=== Disconnecting ===');
  48. await transport.close();
  49. console.log('Disconnected from MCP server');
  50. }
  51. catch (error) {
  52. console.error('Error running client:', error);
  53. process.exit(1);
  54. }
  55. }
  56. /**
  57. * Connect to an MCP server with backwards compatibility
  58. * Following the spec for client backward compatibility
  59. */
  60. async function connectWithBackwardsCompatibility(url) {
  61. console.log('1. Trying Streamable HTTP transport first...');
  62. // Step 1: Try Streamable HTTP transport first
  63. const client = new index_js_1.Client({
  64. name: 'backwards-compatible-client',
  65. version: '1.0.0'
  66. });
  67. client.onerror = error => {
  68. console.error('Client error:', error);
  69. };
  70. const baseUrl = new URL(url);
  71. try {
  72. // Create modern transport
  73. const streamableTransport = new streamableHttp_js_1.StreamableHTTPClientTransport(baseUrl);
  74. await client.connect(streamableTransport);
  75. console.log('Successfully connected using modern Streamable HTTP transport.');
  76. return {
  77. client,
  78. transport: streamableTransport,
  79. transportType: 'streamable-http'
  80. };
  81. }
  82. catch (error) {
  83. // Step 2: If transport fails, try the older SSE transport
  84. console.log(`StreamableHttp transport connection failed: ${error}`);
  85. console.log('2. Falling back to deprecated HTTP+SSE transport...');
  86. try {
  87. // Create SSE transport pointing to /sse endpoint
  88. const sseTransport = new sse_js_1.SSEClientTransport(baseUrl);
  89. const sseClient = new index_js_1.Client({
  90. name: 'backwards-compatible-client',
  91. version: '1.0.0'
  92. });
  93. await sseClient.connect(sseTransport);
  94. console.log('Successfully connected using deprecated HTTP+SSE transport.');
  95. return {
  96. client: sseClient,
  97. transport: sseTransport,
  98. transportType: 'sse'
  99. };
  100. }
  101. catch (sseError) {
  102. console.error(`Failed to connect with either transport method:\n1. Streamable HTTP error: ${error}\n2. SSE error: ${sseError}`);
  103. throw new Error('Could not connect to server with any available transport');
  104. }
  105. }
  106. }
  107. /**
  108. * List available tools on the server
  109. */
  110. async function listTools(client) {
  111. try {
  112. const toolsRequest = {
  113. method: 'tools/list',
  114. params: {}
  115. };
  116. const toolsResult = await client.request(toolsRequest, types_js_1.ListToolsResultSchema);
  117. console.log('Available tools:');
  118. if (toolsResult.tools.length === 0) {
  119. console.log(' No tools available');
  120. }
  121. else {
  122. for (const tool of toolsResult.tools) {
  123. console.log(` - ${tool.name}: ${tool.description}`);
  124. }
  125. }
  126. }
  127. catch (error) {
  128. console.log(`Tools not supported by this server: ${error}`);
  129. }
  130. }
  131. /**
  132. * Start a notification stream by calling the notification tool
  133. */
  134. async function startNotificationTool(client) {
  135. try {
  136. // Call the notification tool using reasonable defaults
  137. const request = {
  138. method: 'tools/call',
  139. params: {
  140. name: 'start-notification-stream',
  141. arguments: {
  142. interval: 1000, // 1 second between notifications
  143. count: 5 // Send 5 notifications
  144. }
  145. }
  146. };
  147. console.log('Calling notification tool...');
  148. const result = await client.request(request, types_js_1.CallToolResultSchema);
  149. console.log('Tool result:');
  150. result.content.forEach(item => {
  151. if (item.type === 'text') {
  152. console.log(` ${item.text}`);
  153. }
  154. else {
  155. console.log(` ${item.type} content:`, item);
  156. }
  157. });
  158. }
  159. catch (error) {
  160. console.log(`Error calling notification tool: ${error}`);
  161. }
  162. }
  163. // Start the client
  164. main().catch((error) => {
  165. console.error('Error running MCP client:', error);
  166. process.exit(1);
  167. });
  168. //# sourceMappingURL=streamableHttpWithSseFallbackClient.js.map