simpleTaskInteractiveClient.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. "use strict";
  2. /**
  3. * Simple interactive task client demonstrating elicitation and sampling responses.
  4. *
  5. * This client connects to simpleTaskInteractive.ts server and demonstrates:
  6. * - Handling elicitation requests (y/n confirmation)
  7. * - Handling sampling requests (returns a hardcoded haiku)
  8. * - Using task-based tool execution with streaming
  9. */
  10. Object.defineProperty(exports, "__esModule", { value: true });
  11. const index_js_1 = require("../../client/index.js");
  12. const streamableHttp_js_1 = require("../../client/streamableHttp.js");
  13. const node_readline_1 = require("node:readline");
  14. const types_js_1 = require("../../types.js");
  15. // Create readline interface for user input
  16. const readline = (0, node_readline_1.createInterface)({
  17. input: process.stdin,
  18. output: process.stdout
  19. });
  20. function question(prompt) {
  21. return new Promise(resolve => {
  22. readline.question(prompt, answer => {
  23. resolve(answer.trim());
  24. });
  25. });
  26. }
  27. function getTextContent(result) {
  28. const textContent = result.content.find((c) => c.type === 'text');
  29. return textContent?.text ?? '(no text)';
  30. }
  31. async function elicitationCallback(params) {
  32. console.log(`\n[Elicitation] Server asks: ${params.message}`);
  33. // Simple terminal prompt for y/n
  34. const response = await question('Your response (y/n): ');
  35. const confirmed = ['y', 'yes', 'true', '1'].includes(response.toLowerCase());
  36. console.log(`[Elicitation] Responding with: confirm=${confirmed}`);
  37. return { action: 'accept', content: { confirm: confirmed } };
  38. }
  39. async function samplingCallback(params) {
  40. // Get the prompt from the first message
  41. let prompt = 'unknown';
  42. if (params.messages && params.messages.length > 0) {
  43. const firstMessage = params.messages[0];
  44. const content = firstMessage.content;
  45. if (typeof content === 'object' && !Array.isArray(content) && content.type === 'text' && 'text' in content) {
  46. prompt = content.text;
  47. }
  48. else if (Array.isArray(content)) {
  49. const textPart = content.find(c => c.type === 'text' && 'text' in c);
  50. if (textPart && 'text' in textPart) {
  51. prompt = textPart.text;
  52. }
  53. }
  54. }
  55. console.log(`\n[Sampling] Server requests LLM completion for: ${prompt}`);
  56. // Return a hardcoded haiku (in real use, call your LLM here)
  57. const haiku = `Cherry blossoms fall
  58. Softly on the quiet pond
  59. Spring whispers goodbye`;
  60. console.log('[Sampling] Responding with haiku');
  61. return {
  62. model: 'mock-haiku-model',
  63. role: 'assistant',
  64. content: { type: 'text', text: haiku }
  65. };
  66. }
  67. async function run(url) {
  68. console.log('Simple Task Interactive Client');
  69. console.log('==============================');
  70. console.log(`Connecting to ${url}...`);
  71. // Create client with elicitation and sampling capabilities
  72. const client = new index_js_1.Client({ name: 'simple-task-interactive-client', version: '1.0.0' }, {
  73. capabilities: {
  74. elicitation: { form: {} },
  75. sampling: {}
  76. }
  77. });
  78. // Set up elicitation request handler
  79. client.setRequestHandler(types_js_1.ElicitRequestSchema, async (request) => {
  80. if (request.params.mode && request.params.mode !== 'form') {
  81. throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Unsupported elicitation mode: ${request.params.mode}`);
  82. }
  83. return elicitationCallback(request.params);
  84. });
  85. // Set up sampling request handler
  86. client.setRequestHandler(types_js_1.CreateMessageRequestSchema, async (request) => {
  87. return samplingCallback(request.params);
  88. });
  89. // Connect to server
  90. const transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(url));
  91. await client.connect(transport);
  92. console.log('Connected!\n');
  93. // List tools
  94. const toolsResult = await client.listTools();
  95. console.log(`Available tools: ${toolsResult.tools.map(t => t.name).join(', ')}`);
  96. // Demo 1: Elicitation (confirm_delete)
  97. console.log('\n--- Demo 1: Elicitation ---');
  98. console.log('Calling confirm_delete tool...');
  99. const confirmStream = client.experimental.tasks.callToolStream({ name: 'confirm_delete', arguments: { filename: 'important.txt' } }, types_js_1.CallToolResultSchema, { task: { ttl: 60000 } });
  100. for await (const message of confirmStream) {
  101. switch (message.type) {
  102. case 'taskCreated':
  103. console.log(`Task created: ${message.task.taskId}`);
  104. break;
  105. case 'taskStatus':
  106. console.log(`Task status: ${message.task.status}`);
  107. break;
  108. case 'result':
  109. console.log(`Result: ${getTextContent(message.result)}`);
  110. break;
  111. case 'error':
  112. console.error(`Error: ${message.error}`);
  113. break;
  114. }
  115. }
  116. // Demo 2: Sampling (write_haiku)
  117. console.log('\n--- Demo 2: Sampling ---');
  118. console.log('Calling write_haiku tool...');
  119. const haikuStream = client.experimental.tasks.callToolStream({ name: 'write_haiku', arguments: { topic: 'autumn leaves' } }, types_js_1.CallToolResultSchema, {
  120. task: { ttl: 60000 }
  121. });
  122. for await (const message of haikuStream) {
  123. switch (message.type) {
  124. case 'taskCreated':
  125. console.log(`Task created: ${message.task.taskId}`);
  126. break;
  127. case 'taskStatus':
  128. console.log(`Task status: ${message.task.status}`);
  129. break;
  130. case 'result':
  131. console.log(`Result:\n${getTextContent(message.result)}`);
  132. break;
  133. case 'error':
  134. console.error(`Error: ${message.error}`);
  135. break;
  136. }
  137. }
  138. // Cleanup
  139. console.log('\nDemo complete. Closing connection...');
  140. await transport.close();
  141. readline.close();
  142. }
  143. // Parse command line arguments
  144. const args = process.argv.slice(2);
  145. let url = 'http://localhost:8000/mcp';
  146. for (let i = 0; i < args.length; i++) {
  147. if (args[i] === '--url' && args[i + 1]) {
  148. url = args[i + 1];
  149. i++;
  150. }
  151. }
  152. // Run the client
  153. run(url).catch(error => {
  154. console.error('Error running client:', error);
  155. process.exit(1);
  156. });
  157. //# sourceMappingURL=simpleTaskInteractiveClient.js.map