avancement planning

This commit is contained in:
2026-05-26 11:58:39 +02:00
parent 619a2b240a
commit 150b97cd2e
4892 changed files with 99214 additions and 429382 deletions
@@ -1,14 +1,11 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
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");
const metadataUtils_js_1 = require("../../shared/metadataUtils.js");
const ajv_1 = __importDefault(require("ajv"));
const ajv_1 = require("ajv");
// Create readline interface for user input
const readline = (0, node_readline_1.createInterface)({
input: process.stdin,
@@ -39,9 +36,10 @@ function printHelp() {
console.log(' reconnect - Reconnect to the server');
console.log(' list-tools - List available tools');
console.log(' call-tool <name> [args] - Call a tool with optional JSON arguments');
console.log(' call-tool-task <name> [args] - Call a tool with task-based execution (example: call-tool-task delay {"duration":3000})');
console.log(' greet [name] - Call the greet tool');
console.log(' multi-greet [name] - Call the multi-greet tool with notifications');
console.log(' collect-info [type] - Test elicitation with collect-user-info tool (contact/preferences/feedback)');
console.log(' collect-info [type] - Test form elicitation with collect-user-info tool (contact/preferences/feedback)');
console.log(' start-notifications [interval] [count] - Start periodic notifications');
console.log(' run-notifications-tool-with-resumability [interval] [count] - Run notification tool with resumability');
console.log(' list-prompts - List available prompts');
@@ -53,9 +51,8 @@ function printHelp() {
}
function commandLoop() {
readline.question('\n> ', async (input) => {
var _a;
const args = input.trim().split(/\s+/);
const command = (_a = args[0]) === null || _a === void 0 ? void 0 : _a.toLowerCase();
const command = args[0]?.toLowerCase();
try {
switch (command) {
case 'connect':
@@ -84,7 +81,7 @@ function commandLoop() {
try {
toolArgs = JSON.parse(args.slice(2).join(' '));
}
catch (_b) {
catch {
console.log('Invalid JSON arguments. Using empty args.');
}
}
@@ -112,6 +109,24 @@ function commandLoop() {
await runNotificationsToolWithResumability(interval, count);
break;
}
case 'call-tool-task':
if (args.length < 2) {
console.log('Usage: call-tool-task <name> [args]');
}
else {
const toolName = args[1];
let toolArgs = {};
if (args.length > 2) {
try {
toolArgs = JSON.parse(args.slice(2).join(' '));
}
catch {
console.log('Invalid JSON arguments. Using empty args.');
}
}
await callToolTask(toolName, toolArgs);
}
break;
case 'list-prompts':
await listPrompts();
break;
@@ -126,7 +141,7 @@ function commandLoop() {
try {
promptArgs = JSON.parse(args.slice(2).join(' '));
}
catch (_c) {
catch {
console.log('Invalid JSON arguments. Using empty args.');
}
}
@@ -175,30 +190,35 @@ async function connect(url) {
}
console.log(`Connecting to ${serverUrl}...`);
try {
// Create a new client with elicitation capability
// Create a new client with form elicitation capability
client = new index_js_1.Client({
name: 'example-client',
version: '1.0.0'
}, {
capabilities: {
elicitation: {},
},
elicitation: {
form: {}
}
}
});
client.onerror = (error) => {
client.onerror = error => {
console.error('\x1b[31mClient error:', error, '\x1b[0m');
};
// Set up elicitation request handler with proper validation
client.setRequestHandler(types_js_1.ElicitRequestSchema, async (request) => {
var _a;
console.log('\n🔔 Elicitation Request Received:');
if (request.params.mode !== 'form') {
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Unsupported elicitation mode: ${request.params.mode}`);
}
console.log('\n🔔 Elicitation (form) Request Received:');
console.log(`Message: ${request.params.message}`);
console.log(`Related Task: ${request.params._meta?.[types_js_1.RELATED_TASK_META_KEY]?.taskId}`);
console.log('Requested Schema:');
console.log(JSON.stringify(request.params.requestedSchema, null, 2));
const schema = request.params.requestedSchema;
const properties = schema.properties;
const required = schema.required || [];
// Set up AJV validator for the requested schema
const ajv = new ajv_1.default();
const ajv = new ajv_1.Ajv();
const validate = ajv.compile(schema);
let attempts = 0;
const maxAttempts = 3;
@@ -240,8 +260,8 @@ async function connect(url) {
prompt += ` [default: ${field.default}]`;
}
prompt += ': ';
const answer = await new Promise((resolve) => {
readline.question(prompt, (input) => {
const answer = await new Promise(resolve => {
readline.question(prompt, input => {
resolve(input.trim());
});
});
@@ -302,7 +322,8 @@ async function connect(url) {
return { action: 'cancel' };
}
// If we didn't complete all fields due to an error, try again
if (Object.keys(content).length !== Object.keys(properties).filter(name => required.includes(name) || content[name] !== undefined).length) {
if (Object.keys(content).length !==
Object.keys(properties).filter(name => required.includes(name) || content[name] !== undefined).length) {
if (attempts < maxAttempts) {
console.log('Please try again...');
continue;
@@ -316,8 +337,8 @@ async function connect(url) {
const isValid = validate(content);
if (!isValid) {
console.log('❌ Validation errors:');
(_a = validate.errors) === null || _a === void 0 ? void 0 : _a.forEach(error => {
console.log(` - ${error.dataPath || 'root'}: ${error.message}`);
validate.errors?.forEach(error => {
console.log(` - ${error.instancePath || 'root'}: ${error.message}`);
});
if (attempts < maxAttempts) {
console.log('Please correct the errors and try again...');
@@ -331,15 +352,15 @@ async function connect(url) {
// Show the collected data and ask for confirmation
console.log('\n✅ Collected data:');
console.log(JSON.stringify(content, null, 2));
const confirmAnswer = await new Promise((resolve) => {
readline.question('\nSubmit this information? (yes/no/cancel): ', (input) => {
const confirmAnswer = await new Promise(resolve => {
readline.question('\nSubmit this information? (yes/no/cancel): ', input => {
resolve(input.trim().toLowerCase());
});
});
if (confirmAnswer === 'yes' || confirmAnswer === 'y') {
return {
action: 'accept',
content,
content
};
}
else if (confirmAnswer === 'cancel' || confirmAnswer === 'c') {
@@ -362,7 +383,7 @@ async function connect(url) {
sessionId: sessionId
});
// Set up notification handlers
client.setNotificationHandler(types_js_1.LoggingMessageNotificationSchema, (notification) => {
client.setNotificationHandler(types_js_1.LoggingMessageNotificationSchema, notification => {
notificationCount++;
console.log(`\nNotification #${notificationCount}: ${notification.params.level} - ${notification.params.data}`);
// Re-display the prompt
@@ -381,7 +402,7 @@ async function connect(url) {
}, types_js_1.ListResourcesResultSchema);
console.log('Available resources count:', resourcesResult.resources.length);
}
catch (_a) {
catch {
console.log('Failed to list resources after change notification');
}
// Re-display the prompt
@@ -536,7 +557,7 @@ async function callMultiGreetTool(name) {
await callTool('multi-greet', { name });
}
async function callCollectInfoTool(infoType) {
console.log(`Testing elicitation with collect-user-info tool (${infoType})...`);
console.log(`Testing form elicitation with collect-user-info tool (${infoType})...`);
await callTool('collect-user-info', { infoType });
}
async function startNotifications(interval, count) {
@@ -621,7 +642,7 @@ async function getPrompt(name, args) {
const promptResult = await client.request(promptRequest, types_js_1.GetPromptResultSchema);
console.log('Prompt template:');
promptResult.messages.forEach((msg, index) => {
console.log(` [${index + 1}] ${msg.role}: ${msg.content.text}`);
console.log(` [${index + 1}] ${msg.role}: ${msg.content.type === 'text' ? msg.content.text : JSON.stringify(msg.content)}`);
});
}
catch (error) {
@@ -674,7 +695,10 @@ async function readResource(uri) {
if ('text' in content && typeof content.text === 'string') {
console.log(' Content:');
console.log(' ---');
console.log(content.text.split('\n').map((line) => ' ' + line).join('\n'));
console.log(content.text
.split('\n')
.map((line) => ' ' + line)
.join('\n'));
console.log(' ---');
}
else if ('blob' in content && typeof content.blob === 'string') {
@@ -686,6 +710,57 @@ async function readResource(uri) {
console.log(`Error reading resource ${uri}: ${error}`);
}
}
async function callToolTask(name, args) {
if (!client) {
console.log('Not connected to server.');
return;
}
console.log(`Calling tool '${name}' with task-based execution...`);
console.log('Arguments:', args);
// Use task-based execution - call now, fetch later
// Using the experimental tasks API - WARNING: may change without notice
console.log('This will return immediately while processing continues in the background...');
try {
// Call the tool with task metadata using streaming API
const stream = client.experimental.tasks.callToolStream({
name,
arguments: args
}, types_js_1.CallToolResultSchema, {
task: {
ttl: 60000 // Keep results for 60 seconds
}
});
console.log('Waiting for task completion...');
let lastStatus = '';
for await (const message of stream) {
switch (message.type) {
case 'taskCreated':
console.log('Task created successfully with ID:', message.task.taskId);
break;
case 'taskStatus':
if (lastStatus !== message.task.status) {
console.log(` ${message.task.status}${message.task.statusMessage ? ` - ${message.task.statusMessage}` : ''}`);
}
lastStatus = message.task.status;
break;
case 'result':
console.log('Task completed!');
console.log('Tool result:');
message.result.content.forEach(item => {
if (item.type === 'text') {
console.log(` ${item.text}`);
}
});
break;
case 'error':
throw message.error;
}
}
}
catch (error) {
console.log(`Error with task-based execution: ${error}`);
}
}
async function cleanup() {
if (client && transport) {
try {