Spaces:
Running
Running
fixing some things before video
Browse files- mcp-server.js +167 -10
- test-mcp-changes.js +210 -0
mcp-server.js
CHANGED
|
@@ -193,10 +193,6 @@ class ReubenOSMCPServer {
|
|
| 193 |
type: 'string',
|
| 194 |
description: 'Song lyrics (will be used to generate music)',
|
| 195 |
},
|
| 196 |
-
passkey: {
|
| 197 |
-
type: 'string',
|
| 198 |
-
description: 'Your passkey for authentication',
|
| 199 |
-
},
|
| 200 |
},
|
| 201 |
required: ['title', 'style', 'lyrics'],
|
| 202 |
},
|
|
@@ -215,12 +211,26 @@ class ReubenOSMCPServer {
|
|
| 215 |
type: 'string',
|
| 216 |
description: 'Story content/text to be narrated (max 2000 characters for best performance)',
|
| 217 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
passkey: {
|
| 219 |
type: 'string',
|
| 220 |
-
description: 'Your passkey for
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
},
|
| 222 |
},
|
| 223 |
-
required: ['
|
| 224 |
},
|
| 225 |
},
|
| 226 |
],
|
|
@@ -245,6 +255,8 @@ class ReubenOSMCPServer {
|
|
| 245 |
return await this.generateSongAudio(args);
|
| 246 |
case 'generate_story_audio':
|
| 247 |
return await this.generateStoryAudio(args);
|
|
|
|
|
|
|
| 248 |
default:
|
| 249 |
throw new Error(`Unknown tool: ${name}`);
|
| 250 |
}
|
|
@@ -377,6 +389,19 @@ class ReubenOSMCPServer {
|
|
| 377 |
};
|
| 378 |
}
|
| 379 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 380 |
const response = await fetch(API_ENDPOINT, {
|
| 381 |
method: 'POST',
|
| 382 |
headers: { 'Content-Type': 'application/json' },
|
|
@@ -384,7 +409,7 @@ class ReubenOSMCPServer {
|
|
| 384 |
passkey,
|
| 385 |
action: 'save_file',
|
| 386 |
fileName,
|
| 387 |
-
content,
|
| 388 |
isPublic,
|
| 389 |
}),
|
| 390 |
});
|
|
@@ -393,12 +418,13 @@ class ReubenOSMCPServer {
|
|
| 393 |
|
| 394 |
if (response.ok && data.success) {
|
| 395 |
const location = isPublic ? 'Public Folder' : `Secure Data (passkey: ${passkey})`;
|
|
|
|
| 396 |
|
| 397 |
return {
|
| 398 |
content: [
|
| 399 |
{
|
| 400 |
type: 'text',
|
| 401 |
-
text: `✅ File saved: ${fileName}\n📁 Saved to: ${location}`,
|
| 402 |
},
|
| 403 |
],
|
| 404 |
};
|
|
@@ -575,7 +601,9 @@ class ReubenOSMCPServer {
|
|
| 575 |
|
| 576 |
async generateSongAudio(args) {
|
| 577 |
try {
|
| 578 |
-
const { title, style, lyrics
|
|
|
|
|
|
|
| 579 |
|
| 580 |
if (!title || !style || !lyrics) {
|
| 581 |
return {
|
|
@@ -624,7 +652,9 @@ class ReubenOSMCPServer {
|
|
| 624 |
|
| 625 |
async generateStoryAudio(args) {
|
| 626 |
try {
|
| 627 |
-
const { title, content
|
|
|
|
|
|
|
| 628 |
|
| 629 |
if (!title || !content) {
|
| 630 |
return {
|
|
@@ -671,6 +701,133 @@ class ReubenOSMCPServer {
|
|
| 671 |
}
|
| 672 |
}
|
| 673 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 674 |
async run() {
|
| 675 |
const transport = new StdioServerTransport();
|
| 676 |
await this.server.connect(transport);
|
|
|
|
| 193 |
type: 'string',
|
| 194 |
description: 'Song lyrics (will be used to generate music)',
|
| 195 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
},
|
| 197 |
required: ['title', 'style', 'lyrics'],
|
| 198 |
},
|
|
|
|
| 211 |
type: 'string',
|
| 212 |
description: 'Story content/text to be narrated (max 2000 characters for best performance)',
|
| 213 |
},
|
| 214 |
+
},
|
| 215 |
+
required: ['title', 'content'],
|
| 216 |
+
},
|
| 217 |
+
},
|
| 218 |
+
{
|
| 219 |
+
name: 'analyze_quiz',
|
| 220 |
+
description: 'Analyze quiz answers from quiz_answers.json against the quiz.json questions and provide feedback on correctness',
|
| 221 |
+
inputSchema: {
|
| 222 |
+
type: 'object',
|
| 223 |
+
properties: {
|
| 224 |
passkey: {
|
| 225 |
type: 'string',
|
| 226 |
+
description: 'Your passkey for accessing the quiz files',
|
| 227 |
+
},
|
| 228 |
+
isPublic: {
|
| 229 |
+
type: 'boolean',
|
| 230 |
+
description: 'Set to true if quiz files are in public folder. Default: false',
|
| 231 |
},
|
| 232 |
},
|
| 233 |
+
required: ['passkey'],
|
| 234 |
},
|
| 235 |
},
|
| 236 |
],
|
|
|
|
| 255 |
return await this.generateSongAudio(args);
|
| 256 |
case 'generate_story_audio':
|
| 257 |
return await this.generateStoryAudio(args);
|
| 258 |
+
case 'analyze_quiz':
|
| 259 |
+
return await this.analyzeQuiz(args);
|
| 260 |
default:
|
| 261 |
throw new Error(`Unknown tool: ${name}`);
|
| 262 |
}
|
|
|
|
| 389 |
};
|
| 390 |
}
|
| 391 |
|
| 392 |
+
// Ensure content is properly stringified if it's an object
|
| 393 |
+
let fileContent = content;
|
| 394 |
+
if (typeof content === 'object' && content !== null) {
|
| 395 |
+
fileContent = JSON.stringify(content, null, 2);
|
| 396 |
+
}
|
| 397 |
+
|
| 398 |
+
// Handle special characters in content for code files
|
| 399 |
+
const ext = fileName.split('.').pop().toLowerCase();
|
| 400 |
+
const isCodeFile = ['dart', 'js', 'ts', 'jsx', 'tsx', 'py', 'java', 'cpp', 'c', 'h', 'hpp', 'cs', 'swift', 'kt', 'go', 'rs', 'rb', 'php'].includes(ext);
|
| 401 |
+
|
| 402 |
+
// Ensure content is a string
|
| 403 |
+
fileContent = String(fileContent);
|
| 404 |
+
|
| 405 |
const response = await fetch(API_ENDPOINT, {
|
| 406 |
method: 'POST',
|
| 407 |
headers: { 'Content-Type': 'application/json' },
|
|
|
|
| 409 |
passkey,
|
| 410 |
action: 'save_file',
|
| 411 |
fileName,
|
| 412 |
+
content: fileContent,
|
| 413 |
isPublic,
|
| 414 |
}),
|
| 415 |
});
|
|
|
|
| 418 |
|
| 419 |
if (response.ok && data.success) {
|
| 420 |
const location = isPublic ? 'Public Folder' : `Secure Data (passkey: ${passkey})`;
|
| 421 |
+
const fileType = isCodeFile ? `(${ext.toUpperCase()} code file)` : '';
|
| 422 |
|
| 423 |
return {
|
| 424 |
content: [
|
| 425 |
{
|
| 426 |
type: 'text',
|
| 427 |
+
text: `✅ File saved: ${fileName} ${fileType}\n📁 Saved to: ${location}\n📊 Size: ${(new TextEncoder().encode(fileContent).length / 1024).toFixed(2)} KB`,
|
| 428 |
},
|
| 429 |
],
|
| 430 |
};
|
|
|
|
| 601 |
|
| 602 |
async generateSongAudio(args) {
|
| 603 |
try {
|
| 604 |
+
const { title, style, lyrics } = args;
|
| 605 |
+
// Use a default passkey internally - users don't need to provide it
|
| 606 |
+
const passkey = 'voice_default';
|
| 607 |
|
| 608 |
if (!title || !style || !lyrics) {
|
| 609 |
return {
|
|
|
|
| 652 |
|
| 653 |
async generateStoryAudio(args) {
|
| 654 |
try {
|
| 655 |
+
const { title, content } = args;
|
| 656 |
+
// Use a default passkey internally - users don't need to provide it
|
| 657 |
+
const passkey = 'voice_default';
|
| 658 |
|
| 659 |
if (!title || !content) {
|
| 660 |
return {
|
|
|
|
| 701 |
}
|
| 702 |
}
|
| 703 |
|
| 704 |
+
async analyzeQuiz(args) {
|
| 705 |
+
try {
|
| 706 |
+
const { passkey, isPublic = false } = args;
|
| 707 |
+
|
| 708 |
+
if (!passkey) {
|
| 709 |
+
return {
|
| 710 |
+
content: [{ type: 'text', text: '❌ Passkey is required to access quiz files' }],
|
| 711 |
+
};
|
| 712 |
+
}
|
| 713 |
+
|
| 714 |
+
// Read quiz.json
|
| 715 |
+
const quizUrl = new URL(API_ENDPOINT);
|
| 716 |
+
quizUrl.searchParams.set('passkey', passkey);
|
| 717 |
+
if (isPublic) quizUrl.searchParams.set('isPublic', 'true');
|
| 718 |
+
|
| 719 |
+
const quizResponse = await fetch(quizUrl, {
|
| 720 |
+
method: 'GET',
|
| 721 |
+
headers: { 'Content-Type': 'application/json' },
|
| 722 |
+
});
|
| 723 |
+
|
| 724 |
+
const quizData = await quizResponse.json();
|
| 725 |
+
|
| 726 |
+
if (!quizResponse.ok || !quizData.success) {
|
| 727 |
+
return {
|
| 728 |
+
content: [{ type: 'text', text: `❌ Failed to read quiz.json: ${quizData.error || 'Unknown error'}` }],
|
| 729 |
+
};
|
| 730 |
+
}
|
| 731 |
+
|
| 732 |
+
const quizFile = quizData.files.find(f => f.name === 'quiz.json');
|
| 733 |
+
if (!quizFile) {
|
| 734 |
+
return {
|
| 735 |
+
content: [{ type: 'text', text: '❌ quiz.json not found in storage' }],
|
| 736 |
+
};
|
| 737 |
+
}
|
| 738 |
+
|
| 739 |
+
// Read quiz_answers.json
|
| 740 |
+
const answersFile = quizData.files.find(f => f.name === 'quiz_answers.json');
|
| 741 |
+
if (!answersFile) {
|
| 742 |
+
return {
|
| 743 |
+
content: [{ type: 'text', text: '❌ quiz_answers.json not found in storage' }],
|
| 744 |
+
};
|
| 745 |
+
}
|
| 746 |
+
|
| 747 |
+
// Parse the quiz and answers
|
| 748 |
+
const quiz = JSON.parse(quizFile.content);
|
| 749 |
+
const answers = JSON.parse(answersFile.content);
|
| 750 |
+
|
| 751 |
+
// Analyze the answers
|
| 752 |
+
let correctCount = 0;
|
| 753 |
+
let totalPoints = 0;
|
| 754 |
+
let maxPoints = 0;
|
| 755 |
+
const feedback = [];
|
| 756 |
+
|
| 757 |
+
quiz.questions.forEach((question, index) => {
|
| 758 |
+
const userAnswer = answers.answers?.[question.id] || answers[question.id];
|
| 759 |
+
const points = question.points || 1;
|
| 760 |
+
maxPoints += points;
|
| 761 |
+
|
| 762 |
+
// For multiple choice questions, check if answer matches any correct option
|
| 763 |
+
if (question.type === 'multiple_choice') {
|
| 764 |
+
const correctAnswer = question.correctAnswer || question.correct;
|
| 765 |
+
const isCorrect = userAnswer === correctAnswer ||
|
| 766 |
+
(Array.isArray(correctAnswer) && correctAnswer.includes(userAnswer));
|
| 767 |
+
|
| 768 |
+
if (isCorrect) {
|
| 769 |
+
correctCount++;
|
| 770 |
+
totalPoints += points;
|
| 771 |
+
feedback.push(`✅ Question ${index + 1} (${question.id}): Correct! (+${points} points)`);
|
| 772 |
+
} else {
|
| 773 |
+
feedback.push(`❌ Question ${index + 1} (${question.id}): Incorrect. Your answer: "${userAnswer}"${question.explanation ? `. ${question.explanation}` : ''}`);
|
| 774 |
+
}
|
| 775 |
+
} else if (question.type === 'true_false') {
|
| 776 |
+
const correctAnswer = question.correctAnswer || question.correct;
|
| 777 |
+
const isCorrect = String(userAnswer).toLowerCase() === String(correctAnswer).toLowerCase();
|
| 778 |
+
|
| 779 |
+
if (isCorrect) {
|
| 780 |
+
correctCount++;
|
| 781 |
+
totalPoints += points;
|
| 782 |
+
feedback.push(`✅ Question ${index + 1} (${question.id}): Correct! (+${points} points)`);
|
| 783 |
+
} else {
|
| 784 |
+
feedback.push(`❌ Question ${index + 1} (${question.id}): Incorrect. Your answer: "${userAnswer}"${question.explanation ? `. ${question.explanation}` : ''}`);
|
| 785 |
+
}
|
| 786 |
+
} else {
|
| 787 |
+
// For other question types, do a simple string comparison
|
| 788 |
+
const correctAnswer = question.correctAnswer || question.answer || question.correct;
|
| 789 |
+
const isCorrect = userAnswer === correctAnswer;
|
| 790 |
+
|
| 791 |
+
if (isCorrect) {
|
| 792 |
+
correctCount++;
|
| 793 |
+
totalPoints += points;
|
| 794 |
+
feedback.push(`✅ Question ${index + 1} (${question.id}): Correct! (+${points} points)`);
|
| 795 |
+
} else {
|
| 796 |
+
feedback.push(`❌ Question ${index + 1} (${question.id}): Your answer: "${userAnswer}"${question.explanation ? `. ${question.explanation}` : ''}`);
|
| 797 |
+
}
|
| 798 |
+
}
|
| 799 |
+
});
|
| 800 |
+
|
| 801 |
+
const percentage = Math.round((totalPoints / maxPoints) * 100);
|
| 802 |
+
const grade = percentage >= 90 ? 'A' :
|
| 803 |
+
percentage >= 80 ? 'B' :
|
| 804 |
+
percentage >= 70 ? 'C' :
|
| 805 |
+
percentage >= 60 ? 'D' : 'F';
|
| 806 |
+
|
| 807 |
+
return {
|
| 808 |
+
content: [
|
| 809 |
+
{
|
| 810 |
+
type: 'text',
|
| 811 |
+
text: `📊 Quiz Analysis Results for "${quiz.title}"
|
| 812 |
+
|
| 813 |
+
📈 Score: ${totalPoints}/${maxPoints} points (${percentage}%)
|
| 814 |
+
✅ Correct Answers: ${correctCount}/${quiz.questions.length}
|
| 815 |
+
🎯 Grade: ${grade}
|
| 816 |
+
|
| 817 |
+
📝 Question Feedback:
|
| 818 |
+
${feedback.join('\n')}
|
| 819 |
+
|
| 820 |
+
${percentage >= 70 ? '🎉 Great job!' : '📚 Keep studying and try again!'}`,
|
| 821 |
+
},
|
| 822 |
+
],
|
| 823 |
+
};
|
| 824 |
+
} catch (error) {
|
| 825 |
+
return {
|
| 826 |
+
content: [{ type: 'text', text: `❌ Error analyzing quiz: ${error.message}` }],
|
| 827 |
+
};
|
| 828 |
+
}
|
| 829 |
+
}
|
| 830 |
+
|
| 831 |
async run() {
|
| 832 |
const transport = new StdioServerTransport();
|
| 833 |
await this.server.connect(transport);
|
test-mcp-changes.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env node
|
| 2 |
+
// Test script for MCP server changes
|
| 3 |
+
|
| 4 |
+
import fetch from 'node-fetch';
|
| 5 |
+
|
| 6 |
+
const BASE_URL = process.env.REUBENOS_URL || 'http://localhost:3000';
|
| 7 |
+
const API_ENDPOINT = `${BASE_URL}/api/mcp-handler`;
|
| 8 |
+
|
| 9 |
+
async function testFlutterCodeSave() {
|
| 10 |
+
console.log('Testing Flutter code save...');
|
| 11 |
+
|
| 12 |
+
const flutterCode = `import 'package:flutter/material.dart';
|
| 13 |
+
|
| 14 |
+
void main() {
|
| 15 |
+
runApp(MyApp());
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
class MyApp extends StatelessWidget {
|
| 19 |
+
@override
|
| 20 |
+
Widget build(BuildContext context) {
|
| 21 |
+
return MaterialApp(
|
| 22 |
+
title: 'Flutter Demo',
|
| 23 |
+
theme: ThemeData(
|
| 24 |
+
primarySwatch: Colors.blue,
|
| 25 |
+
),
|
| 26 |
+
home: MyHomePage(title: 'Flutter Demo Home Page'),
|
| 27 |
+
);
|
| 28 |
+
}
|
| 29 |
+
}
|
| 30 |
+
|
| 31 |
+
class MyHomePage extends StatefulWidget {
|
| 32 |
+
MyHomePage({Key? key, required this.title}) : super(key: key);
|
| 33 |
+
final String title;
|
| 34 |
+
|
| 35 |
+
@override
|
| 36 |
+
_MyHomePageState createState() => _MyHomePageState();
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
class _MyHomePageState extends State<MyHomePage> {
|
| 40 |
+
int _counter = 0;
|
| 41 |
+
|
| 42 |
+
void _incrementCounter() {
|
| 43 |
+
setState(() {
|
| 44 |
+
_counter++;
|
| 45 |
+
});
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
@override
|
| 49 |
+
Widget build(BuildContext context) {
|
| 50 |
+
return Scaffold(
|
| 51 |
+
appBar: AppBar(
|
| 52 |
+
title: Text(widget.title),
|
| 53 |
+
),
|
| 54 |
+
body: Center(
|
| 55 |
+
child: Column(
|
| 56 |
+
mainAxisAlignment: MainAxisAlignment.center,
|
| 57 |
+
children: <Widget>[
|
| 58 |
+
Text(
|
| 59 |
+
'You have pushed the button this many times:',
|
| 60 |
+
),
|
| 61 |
+
Text(
|
| 62 |
+
'$_counter',
|
| 63 |
+
style: Theme.of(context).textTheme.headline4,
|
| 64 |
+
),
|
| 65 |
+
],
|
| 66 |
+
),
|
| 67 |
+
),
|
| 68 |
+
floatingActionButton: FloatingActionButton(
|
| 69 |
+
onPressed: _incrementCounter,
|
| 70 |
+
tooltip: 'Increment',
|
| 71 |
+
child: Icon(Icons.add),
|
| 72 |
+
),
|
| 73 |
+
);
|
| 74 |
+
}
|
| 75 |
+
}`;
|
| 76 |
+
|
| 77 |
+
try {
|
| 78 |
+
const response = await fetch(API_ENDPOINT, {
|
| 79 |
+
method: 'POST',
|
| 80 |
+
headers: { 'Content-Type': 'application/json' },
|
| 81 |
+
body: JSON.stringify({
|
| 82 |
+
passkey: 'test123',
|
| 83 |
+
action: 'save_file',
|
| 84 |
+
fileName: 'main.dart',
|
| 85 |
+
content: flutterCode,
|
| 86 |
+
isPublic: false,
|
| 87 |
+
}),
|
| 88 |
+
});
|
| 89 |
+
|
| 90 |
+
const data = await response.json();
|
| 91 |
+
console.log('Flutter code save result:', data);
|
| 92 |
+
|
| 93 |
+
if (data.success) {
|
| 94 |
+
console.log('✅ Flutter code saved successfully!');
|
| 95 |
+
|
| 96 |
+
// Try to read it back
|
| 97 |
+
const readUrl = new URL(API_ENDPOINT);
|
| 98 |
+
readUrl.searchParams.set('passkey', 'test123');
|
| 99 |
+
|
| 100 |
+
const readResponse = await fetch(readUrl, {
|
| 101 |
+
method: 'GET',
|
| 102 |
+
headers: { 'Content-Type': 'application/json' },
|
| 103 |
+
});
|
| 104 |
+
|
| 105 |
+
const readData = await readResponse.json();
|
| 106 |
+
if (readData.success) {
|
| 107 |
+
const file = readData.files.find(f => f.name === 'main.dart');
|
| 108 |
+
if (file && file.content === flutterCode) {
|
| 109 |
+
console.log('✅ Flutter code verified - content matches!');
|
| 110 |
+
} else {
|
| 111 |
+
console.log('⚠️ Flutter code content mismatch or file not found');
|
| 112 |
+
}
|
| 113 |
+
}
|
| 114 |
+
} else {
|
| 115 |
+
console.log('❌ Failed to save Flutter code:', data.error);
|
| 116 |
+
}
|
| 117 |
+
} catch (error) {
|
| 118 |
+
console.error('Error testing Flutter code save:', error);
|
| 119 |
+
}
|
| 120 |
+
}
|
| 121 |
+
|
| 122 |
+
async function testAnalyzeQuiz() {
|
| 123 |
+
console.log('\nTesting analyze quiz functionality...');
|
| 124 |
+
|
| 125 |
+
// First, create a sample quiz
|
| 126 |
+
const quiz = {
|
| 127 |
+
title: "Sample Quiz",
|
| 128 |
+
description: "Test quiz for analysis",
|
| 129 |
+
questions: [
|
| 130 |
+
{
|
| 131 |
+
id: "q1",
|
| 132 |
+
type: "multiple_choice",
|
| 133 |
+
question: "What is 2+2?",
|
| 134 |
+
options: ["3", "4", "5", "6"],
|
| 135 |
+
correctAnswer: "4",
|
| 136 |
+
points: 1
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
id: "q2",
|
| 140 |
+
type: "multiple_choice",
|
| 141 |
+
question: "What is the capital of France?",
|
| 142 |
+
options: ["London", "Berlin", "Paris", "Madrid"],
|
| 143 |
+
correctAnswer: "Paris",
|
| 144 |
+
points: 1
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
id: "q3",
|
| 148 |
+
type: "true_false",
|
| 149 |
+
question: "The Earth is flat",
|
| 150 |
+
correctAnswer: false,
|
| 151 |
+
points: 1
|
| 152 |
+
}
|
| 153 |
+
]
|
| 154 |
+
};
|
| 155 |
+
|
| 156 |
+
const quizAnswers = {
|
| 157 |
+
answers: {
|
| 158 |
+
"q1": "4",
|
| 159 |
+
"q2": "London",
|
| 160 |
+
"q3": false
|
| 161 |
+
}
|
| 162 |
+
};
|
| 163 |
+
|
| 164 |
+
try {
|
| 165 |
+
// Save quiz.json
|
| 166 |
+
await fetch(API_ENDPOINT, {
|
| 167 |
+
method: 'POST',
|
| 168 |
+
headers: { 'Content-Type': 'application/json' },
|
| 169 |
+
body: JSON.stringify({
|
| 170 |
+
passkey: 'test123',
|
| 171 |
+
action: 'save_file',
|
| 172 |
+
fileName: 'quiz.json',
|
| 173 |
+
content: JSON.stringify(quiz, null, 2),
|
| 174 |
+
isPublic: false,
|
| 175 |
+
}),
|
| 176 |
+
});
|
| 177 |
+
|
| 178 |
+
// Save quiz_answers.json
|
| 179 |
+
await fetch(API_ENDPOINT, {
|
| 180 |
+
method: 'POST',
|
| 181 |
+
headers: { 'Content-Type': 'application/json' },
|
| 182 |
+
body: JSON.stringify({
|
| 183 |
+
passkey: 'test123',
|
| 184 |
+
action: 'save_file',
|
| 185 |
+
fileName: 'quiz_answers.json',
|
| 186 |
+
content: JSON.stringify(quizAnswers, null, 2),
|
| 187 |
+
isPublic: false,
|
| 188 |
+
}),
|
| 189 |
+
});
|
| 190 |
+
|
| 191 |
+
console.log('✅ Quiz and answers saved. Ready to test analyze function.');
|
| 192 |
+
console.log('Note: The analyze_quiz function needs to be called through the MCP server.');
|
| 193 |
+
console.log('Expected results: 2/3 correct (q1 ✅, q2 ❌, q3 ✅)');
|
| 194 |
+
} catch (error) {
|
| 195 |
+
console.error('Error setting up quiz test:', error);
|
| 196 |
+
}
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
// Run tests
|
| 200 |
+
console.log('Starting MCP server tests...');
|
| 201 |
+
console.log('Using server:', BASE_URL);
|
| 202 |
+
|
| 203 |
+
testFlutterCodeSave().then(() => {
|
| 204 |
+
return testAnalyzeQuiz();
|
| 205 |
+
}).then(() => {
|
| 206 |
+
console.log('\n✅ All tests completed!');
|
| 207 |
+
console.log('Note: To fully test the analyze_quiz function, use the MCP client with the analyze_quiz tool.');
|
| 208 |
+
}).catch(error => {
|
| 209 |
+
console.error('Test failed:', error);
|
| 210 |
+
});
|