File size: 6,533 Bytes
a5d718a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"use strict";
/**

 * Simple interactive task client demonstrating elicitation and sampling responses.

 *

 * This client connects to simpleTaskInteractive.ts server and demonstrates:

 * - Handling elicitation requests (y/n confirmation)

 * - Handling sampling requests (returns a hardcoded haiku)

 * - Using task-based tool execution with streaming

 */
Object.defineProperty(exports, "__esModule", { value: true });
const index_js_1 = require("../../client/index.js");
const streamableHttp_js_1 = require("../../client/streamableHttp.js");
const node_readline_1 = require("node:readline");
const types_js_1 = require("../../types.js");
// Create readline interface for user input
const readline = (0, node_readline_1.createInterface)({
    input: process.stdin,
    output: process.stdout
});
function question(prompt) {
    return new Promise(resolve => {
        readline.question(prompt, answer => {
            resolve(answer.trim());
        });
    });
}
function getTextContent(result) {
    const textContent = result.content.find((c) => c.type === 'text');
    return textContent?.text ?? '(no text)';
}
async function elicitationCallback(params) {
    console.log(`\n[Elicitation] Server asks: ${params.message}`);
    // Simple terminal prompt for y/n
    const response = await question('Your response (y/n): ');
    const confirmed = ['y', 'yes', 'true', '1'].includes(response.toLowerCase());
    console.log(`[Elicitation] Responding with: confirm=${confirmed}`);
    return { action: 'accept', content: { confirm: confirmed } };
}
async function samplingCallback(params) {
    // Get the prompt from the first message
    let prompt = 'unknown';
    if (params.messages && params.messages.length > 0) {
        const firstMessage = params.messages[0];
        const content = firstMessage.content;
        if (typeof content === 'object' && !Array.isArray(content) && content.type === 'text' && 'text' in content) {
            prompt = content.text;
        }
        else if (Array.isArray(content)) {
            const textPart = content.find(c => c.type === 'text' && 'text' in c);
            if (textPart && 'text' in textPart) {
                prompt = textPart.text;
            }
        }
    }
    console.log(`\n[Sampling] Server requests LLM completion for: ${prompt}`);
    // Return a hardcoded haiku (in real use, call your LLM here)
    const haiku = `Cherry blossoms fall

Softly on the quiet pond

Spring whispers goodbye`;
    console.log('[Sampling] Responding with haiku');
    return {
        model: 'mock-haiku-model',
        role: 'assistant',
        content: { type: 'text', text: haiku }
    };
}
async function run(url) {
    console.log('Simple Task Interactive Client');
    console.log('==============================');
    console.log(`Connecting to ${url}...`);
    // Create client with elicitation and sampling capabilities
    const client = new index_js_1.Client({ name: 'simple-task-interactive-client', version: '1.0.0' }, {
        capabilities: {
            elicitation: { form: {} },
            sampling: {}
        }
    });
    // Set up elicitation request handler
    client.setRequestHandler(types_js_1.ElicitRequestSchema, async (request) => {
        if (request.params.mode && request.params.mode !== 'form') {
            throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Unsupported elicitation mode: ${request.params.mode}`);
        }
        return elicitationCallback(request.params);
    });
    // Set up sampling request handler
    client.setRequestHandler(types_js_1.CreateMessageRequestSchema, async (request) => {
        return samplingCallback(request.params);
    });
    // Connect to server
    const transport = new streamableHttp_js_1.StreamableHTTPClientTransport(new URL(url));
    await client.connect(transport);
    console.log('Connected!\n');
    // List tools
    const toolsResult = await client.listTools();
    console.log(`Available tools: ${toolsResult.tools.map(t => t.name).join(', ')}`);
    // Demo 1: Elicitation (confirm_delete)
    console.log('\n--- Demo 1: Elicitation ---');
    console.log('Calling confirm_delete tool...');
    const confirmStream = client.experimental.tasks.callToolStream({ name: 'confirm_delete', arguments: { filename: 'important.txt' } }, types_js_1.CallToolResultSchema, { task: { ttl: 60000 } });
    for await (const message of confirmStream) {
        switch (message.type) {
            case 'taskCreated':
                console.log(`Task created: ${message.task.taskId}`);
                break;
            case 'taskStatus':
                console.log(`Task status: ${message.task.status}`);
                break;
            case 'result':
                console.log(`Result: ${getTextContent(message.result)}`);
                break;
            case 'error':
                console.error(`Error: ${message.error}`);
                break;
        }
    }
    // Demo 2: Sampling (write_haiku)
    console.log('\n--- Demo 2: Sampling ---');
    console.log('Calling write_haiku tool...');
    const haikuStream = client.experimental.tasks.callToolStream({ name: 'write_haiku', arguments: { topic: 'autumn leaves' } }, types_js_1.CallToolResultSchema, {
        task: { ttl: 60000 }
    });
    for await (const message of haikuStream) {
        switch (message.type) {
            case 'taskCreated':
                console.log(`Task created: ${message.task.taskId}`);
                break;
            case 'taskStatus':
                console.log(`Task status: ${message.task.status}`);
                break;
            case 'result':
                console.log(`Result:\n${getTextContent(message.result)}`);
                break;
            case 'error':
                console.error(`Error: ${message.error}`);
                break;
        }
    }
    // Cleanup
    console.log('\nDemo complete. Closing connection...');
    await transport.close();
    readline.close();
}
// Parse command line arguments
const args = process.argv.slice(2);
let url = 'http://localhost:8000/mcp';
for (let i = 0; i < args.length; i++) {
    if (args[i] === '--url' && args[i + 1]) {
        url = args[i + 1];
        i++;
    }
}
// Run the client
run(url).catch(error => {
    console.error('Error running client:', error);
    process.exit(1);
});
//# sourceMappingURL=simpleTaskInteractiveClient.js.map