Reubencf commited on
Commit
3ed6d7f
Β·
1 Parent(s): e9d7b34

testing mcp

Browse files
.claude/settings.local.json CHANGED
@@ -27,7 +27,9 @@
27
  "mcp__puppeteer__puppeteer_screenshot",
28
  "mcp__puppeteer__puppeteer_click",
29
  "mcp__puppeteer__puppeteer_evaluate",
30
- "mcp__sequential-thinking__sequentialthinking"
 
 
31
  ],
32
  "deny": [],
33
  "ask": []
 
27
  "mcp__puppeteer__puppeteer_screenshot",
28
  "mcp__puppeteer__puppeteer_click",
29
  "mcp__puppeteer__puppeteer_evaluate",
30
+ "mcp__sequential-thinking__sequentialthinking",
31
+ "Bash(node test-api.js:*)",
32
+ "Bash(REUBENOS_URL=https://huggingface.co/spaces/MCP-1st-Birthday/Reuben_OS node test-api.js:*)"
33
  ],
34
  "deny": [],
35
  "ask": []
DEPLOYMENT_FIX.md ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # πŸ”§ Fix for Reuben OS Quiz & File Saving Issues
2
+
3
+ ## The Problem
4
+ Your Hugging Face Space is using the OLD API structure. The quiz and file saving appear to work in Claude but don't actually save because the Hugging Face deployment doesn't have the new `/api/mcp-handler` route.
5
+
6
+ ## Quick Solution
7
+
8
+ ### Option 1: Deploy to Hugging Face (Recommended)
9
+
10
+ 1. **Push these files to your Hugging Face Space:**
11
+ ```bash
12
+ # In your Hugging Face Space repository
13
+ cp /Users/reubenfernandes/Desktop/Mcp-hackathon-winter25/pages/api/mcp-handler.js pages/api/
14
+ git add pages/api/mcp-handler.js
15
+ git commit -m "Add new MCP handler with session prefix strategy"
16
+ git push
17
+ ```
18
+
19
+ 2. **Restart Claude Desktop** with the new configuration
20
+
21
+ 3. **Test with your session ID:**
22
+ - Session: `session_1763722877048_527d6bb8b7473568`
23
+ - Tell Claude: "Save a test file to my session"
24
+
25
+ ### Option 2: Test Locally First
26
+
27
+ 1. **Start your local Next.js server:**
28
+ ```bash
29
+ cd /Users/reubenfernandes/Desktop/Mcp-hackathon-winter25
30
+ npm run dev
31
+ ```
32
+
33
+ 2. **Update Claude Desktop config to use local URL:**
34
+ ```json
35
+ {
36
+ "mcpServers": {
37
+ "reubenos": {
38
+ "command": "node",
39
+ "args": ["/Users/reubenfernandes/Desktop/Mcp-hackathon-winter25/mcp-server.js"],
40
+ "env": {
41
+ "REUBENOS_URL": "http://localhost:3000"
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ 3. **Test the functionality locally**
49
+
50
+ ## What We Fixed
51
+
52
+ ### βœ… Simplified Architecture
53
+ - Only 2 MCP tools: `manage_files` and `deploy_quiz`
54
+ - Stateless prefix strategy: `{sessionId}_{filename}`
55
+ - No complex session management
56
+
57
+ ### βœ… New Features
58
+ - Save to public folder: `action: "save_public"`
59
+ - Automatic quiz detection
60
+ - Clean file names (prefixes hidden from users)
61
+
62
+ ### βœ… File Structure
63
+ ```
64
+ /tmp/
65
+ session_1763722877048_527d6bb8b7473568_quiz.json
66
+ session_1763722877048_527d6bb8b7473568_main.dart
67
+ session_1763722877048_527d6bb8b7473568_japanese_song.txt
68
+
69
+ /public/uploads/
70
+ public_files_here.txt (no session prefix)
71
+ ```
72
+
73
+ ## Testing Your Fix
74
+
75
+ Run this command to verify everything works:
76
+ ```bash
77
+ node test-api.js
78
+ ```
79
+
80
+ You should see:
81
+ - βœ… File save: SUCCESS
82
+ - βœ… Quiz deploy: SUCCESS
83
+ - βœ… File retrieval: SUCCESS
84
+ - βœ… Public save: SUCCESS
85
+
86
+ ## Current Status
87
+
88
+ βœ… **MCP Server**: Updated and ready
89
+ βœ… **API Route**: Created but needs deployment
90
+ ❌ **Hugging Face**: Still using old API
91
+ ⏳ **Quiz Display**: Will work after deployment
92
+
93
+ ## Next Steps
94
+
95
+ 1. Deploy the new API route to Hugging Face
96
+ 2. Your quiz and file saving will work immediately
97
+ 3. No changes needed to the frontend (it already polls correctly)
98
+
99
+ The Japanese song and quiz you tried to save will work as soon as you deploy the new API route!
claude-desktop-config.json ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "mcpServers": {
3
+ "reubenos": {
4
+ "command": "node",
5
+ "args": ["/Users/reubenfernandes/Desktop/Mcp-hackathon-winter25/mcp-server.js"],
6
+ "env": {
7
+ "REUBENOS_URL": "https://huggingface.co/spaces/MCP-1st-Birthday/Reuben_OS"
8
+ }
9
+ }
10
+ }
11
+ }
mcp-server.js CHANGED
@@ -9,7 +9,7 @@ import {
9
  } from '@modelcontextprotocol/sdk/types.js';
10
  import fetch from 'node-fetch';
11
 
12
- const BASE_URL = process.env.REUBENOS_URL || 'http://localhost:3000';
13
  const API_ENDPOINT = `${BASE_URL}/api/mcp-handler`;
14
 
15
  class ReubenOSMCPServer {
@@ -53,8 +53,8 @@ class ReubenOSMCPServer {
53
  },
54
  action: {
55
  type: 'string',
56
- enum: ['save', 'retrieve', 'delete', 'clear'],
57
- description: 'Action to perform',
58
  },
59
  fileName: {
60
  type: 'string',
@@ -196,13 +196,14 @@ class ReubenOSMCPServer {
196
 
197
  // Handle different actions
198
  switch (args.action) {
199
- case 'save': {
 
200
  const response = await fetch(API_ENDPOINT, {
201
  method: 'POST',
202
  headers: { 'Content-Type': 'application/json' },
203
  body: JSON.stringify({
204
  sessionId: args.sessionId,
205
- action: 'save_file',
206
  fileName: args.fileName,
207
  content: args.content,
208
  }),
@@ -211,11 +212,12 @@ class ReubenOSMCPServer {
211
  const data = await response.json();
212
 
213
  if (response.ok && data.success) {
 
214
  return {
215
  content: [
216
  {
217
  type: 'text',
218
- text: `βœ… File saved successfully!\n\nπŸ“„ File: ${args.fileName}\nπŸ”‘ Session: ${args.sessionId}\n\n✨ File is now available in Reuben OS`,
219
  },
220
  ],
221
  };
 
9
  } from '@modelcontextprotocol/sdk/types.js';
10
  import fetch from 'node-fetch';
11
 
12
+ const BASE_URL = process.env.REUBENOS_URL || 'https://huggingface.co/spaces/MCP-1st-Birthday/Reuben_OS';
13
  const API_ENDPOINT = `${BASE_URL}/api/mcp-handler`;
14
 
15
  class ReubenOSMCPServer {
 
53
  },
54
  action: {
55
  type: 'string',
56
+ enum: ['save', 'retrieve', 'delete', 'clear', 'save_public'],
57
+ description: 'Action to perform (use save_public to save to public folder)',
58
  },
59
  fileName: {
60
  type: 'string',
 
196
 
197
  // Handle different actions
198
  switch (args.action) {
199
+ case 'save':
200
+ case 'save_public': {
201
  const response = await fetch(API_ENDPOINT, {
202
  method: 'POST',
203
  headers: { 'Content-Type': 'application/json' },
204
  body: JSON.stringify({
205
  sessionId: args.sessionId,
206
+ action: args.action === 'save_public' ? 'save_public' : 'save_file',
207
  fileName: args.fileName,
208
  content: args.content,
209
  }),
 
212
  const data = await response.json();
213
 
214
  if (response.ok && data.success) {
215
+ const location = args.action === 'save_public' ? 'πŸ“’ Public Folder' : `πŸ”‘ Session: ${args.sessionId}`;
216
  return {
217
  content: [
218
  {
219
  type: 'text',
220
+ text: `βœ… File saved successfully!\n\nπŸ“„ File: ${args.fileName}\n${location}\n\n✨ File is now available in Reuben OS${args.action === 'save_public' ? ' (publicly accessible)' : ''}`,
221
  },
222
  ],
223
  };
pages/api/mcp-handler.js CHANGED
@@ -2,14 +2,23 @@
2
  import fs from 'fs/promises';
3
  import path from 'path';
4
 
5
- // Ensure /tmp directory exists
6
- async function ensureTmpDirectory() {
 
7
  const tmpPath = '/tmp';
8
  try {
9
  await fs.access(tmpPath);
10
  } catch {
11
  await fs.mkdir(tmpPath, { recursive: true });
12
  }
 
 
 
 
 
 
 
 
13
  }
14
 
15
  // Validate session ID format (alphanumeric and underscores only)
@@ -33,7 +42,7 @@ export default async function handler(req, res) {
33
  }
34
 
35
  try {
36
- await ensureTmpDirectory();
37
 
38
  if (req.method === 'POST') {
39
  // Handle file save/quiz deployment
@@ -56,15 +65,16 @@ export default async function handler(req, res) {
56
  }
57
 
58
  const sanitizedFileName = sanitizeFileName(fileName);
59
- const prefixedFileName = `${sessionId}_${sanitizedFileName}`;
60
- const filePath = path.join('/tmp', prefixedFileName);
61
 
62
  try {
63
  // Handle different actions
64
  switch (action) {
65
  case 'save_file':
66
- case 'deploy_quiz':
67
- // Write content to file
 
 
 
68
  await fs.writeFile(filePath, content, 'utf8');
69
 
70
  return res.status(200).json({
@@ -74,9 +84,28 @@ export default async function handler(req, res) {
74
  prefixedFileName: prefixedFileName,
75
  action: action
76
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
 
78
- case 'delete_file':
79
- // Delete specific file
80
  try {
81
  await fs.unlink(filePath);
82
  return res.status(200).json({
@@ -90,6 +119,7 @@ export default async function handler(req, res) {
90
  error: 'File not found'
91
  });
92
  }
 
93
 
94
  case 'clear_session':
95
  // Clear all files for this session
 
2
  import fs from 'fs/promises';
3
  import path from 'path';
4
 
5
+ // Ensure directories exist
6
+ async function ensureDirectories() {
7
+ // Ensure /tmp directory exists
8
  const tmpPath = '/tmp';
9
  try {
10
  await fs.access(tmpPath);
11
  } catch {
12
  await fs.mkdir(tmpPath, { recursive: true });
13
  }
14
+
15
+ // Ensure public uploads directory exists
16
+ const publicPath = path.join(process.cwd(), 'public', 'uploads');
17
+ try {
18
+ await fs.access(publicPath);
19
+ } catch {
20
+ await fs.mkdir(publicPath, { recursive: true });
21
+ }
22
  }
23
 
24
  // Validate session ID format (alphanumeric and underscores only)
 
42
  }
43
 
44
  try {
45
+ await ensureDirectories();
46
 
47
  if (req.method === 'POST') {
48
  // Handle file save/quiz deployment
 
65
  }
66
 
67
  const sanitizedFileName = sanitizeFileName(fileName);
 
 
68
 
69
  try {
70
  // Handle different actions
71
  switch (action) {
72
  case 'save_file':
73
+ case 'deploy_quiz': {
74
+ // Save to /tmp with session prefix
75
+ const prefixedFileName = `${sessionId}_${sanitizedFileName}`;
76
+ const filePath = path.join('/tmp', prefixedFileName);
77
+
78
  await fs.writeFile(filePath, content, 'utf8');
79
 
80
  return res.status(200).json({
 
84
  prefixedFileName: prefixedFileName,
85
  action: action
86
  });
87
+ }
88
+
89
+ case 'save_public': {
90
+ // Save to public/uploads without session prefix
91
+ const publicPath = path.join(process.cwd(), 'public', 'uploads', sanitizedFileName);
92
+
93
+ await fs.writeFile(publicPath, content, 'utf8');
94
+
95
+ return res.status(200).json({
96
+ success: true,
97
+ message: `File saved to public folder`,
98
+ fileName: sanitizedFileName,
99
+ isPublic: true,
100
+ action: action
101
+ });
102
+ }
103
+
104
+ case 'delete_file': {
105
+ // Delete specific file from /tmp
106
+ const prefixedFileName = `${sessionId}_${sanitizedFileName}`;
107
+ const filePath = path.join('/tmp', prefixedFileName);
108
 
 
 
109
  try {
110
  await fs.unlink(filePath);
111
  return res.status(200).json({
 
119
  error: 'File not found'
120
  });
121
  }
122
+ }
123
 
124
  case 'clear_session':
125
  // Clear all files for this session
test-api.js ADDED
@@ -0,0 +1,128 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // test-api.js - Test script to verify the API is working
2
+ // Run this with: node test-api.js
3
+
4
+ const API_URL = process.env.API_URL || 'https://huggingface.co/spaces/MCP-1st-Birthday/Reuben_OS';
5
+
6
+ async function testAPI() {
7
+ const sessionId = 'session_1763722877048_527d6bb8b7473568';
8
+
9
+ console.log('πŸ” Testing Reuben OS API...\n');
10
+ console.log(`API URL: ${API_URL}`);
11
+ console.log(`Session ID: ${sessionId}\n`);
12
+
13
+ try {
14
+ // Test 1: Save a regular file
15
+ console.log('πŸ“ Test 1: Saving a regular file...');
16
+ const saveResponse = await fetch(`${API_URL}/api/mcp-handler`, {
17
+ method: 'POST',
18
+ headers: { 'Content-Type': 'application/json' },
19
+ body: JSON.stringify({
20
+ sessionId: sessionId,
21
+ action: 'save_file',
22
+ fileName: 'test.txt',
23
+ content: 'This is a test file created at ' + new Date().toISOString()
24
+ })
25
+ });
26
+
27
+ const saveData = await saveResponse.json();
28
+ console.log('Save response:', saveData);
29
+ console.log('βœ… File save:', saveData.success ? 'SUCCESS' : 'FAILED');
30
+ console.log('');
31
+
32
+ // Test 2: Deploy a quiz
33
+ console.log('🎯 Test 2: Deploying a quiz...');
34
+ const quizData = {
35
+ title: 'Test Quiz',
36
+ description: 'A simple test quiz',
37
+ questions: [
38
+ {
39
+ id: 'q1',
40
+ question: 'Is this working?',
41
+ type: 'true-false',
42
+ correctAnswer: true,
43
+ points: 1
44
+ }
45
+ ]
46
+ };
47
+
48
+ const quizResponse = await fetch(`${API_URL}/api/mcp-handler`, {
49
+ method: 'POST',
50
+ headers: { 'Content-Type': 'application/json' },
51
+ body: JSON.stringify({
52
+ sessionId: sessionId,
53
+ action: 'deploy_quiz',
54
+ fileName: 'quiz.json',
55
+ content: JSON.stringify(quizData, null, 2)
56
+ })
57
+ });
58
+
59
+ const quizResponseData = await quizResponse.json();
60
+ console.log('Quiz response:', quizResponseData);
61
+ console.log('βœ… Quiz deploy:', quizResponseData.success ? 'SUCCESS' : 'FAILED');
62
+ console.log('');
63
+
64
+ // Test 3: Retrieve files
65
+ console.log('πŸ“‚ Test 3: Retrieving files for session...');
66
+ const getResponse = await fetch(`${API_URL}/api/mcp-handler?sessionId=${sessionId}`, {
67
+ method: 'GET',
68
+ headers: { 'Content-Type': 'application/json' }
69
+ });
70
+
71
+ const getData = await getResponse.json();
72
+ console.log('Retrieve response:', {
73
+ success: getData.success,
74
+ fileCount: getData.count,
75
+ files: getData.files?.map(f => ({
76
+ name: f.name,
77
+ size: f.size,
78
+ isQuiz: f.isQuiz
79
+ }))
80
+ });
81
+ console.log('βœ… File retrieval:', getData.success ? 'SUCCESS' : 'FAILED');
82
+
83
+ if (getData.success && getData.files) {
84
+ console.log('\nπŸ“‹ Files found:');
85
+ getData.files.forEach(file => {
86
+ console.log(` - ${file.name} (${file.size} bytes)${file.isQuiz ? ' [QUIZ]' : ''}`);
87
+ if (file.name === 'quiz.json' && file.content) {
88
+ console.log(' Quiz content preview:', file.content.substring(0, 100) + '...');
89
+ }
90
+ });
91
+ }
92
+
93
+ // Test 4: Save to public folder
94
+ console.log('\nπŸ“’ Test 4: Saving to public folder...');
95
+ const publicResponse = await fetch(`${API_URL}/api/mcp-handler`, {
96
+ method: 'POST',
97
+ headers: { 'Content-Type': 'application/json' },
98
+ body: JSON.stringify({
99
+ sessionId: sessionId,
100
+ action: 'save_public',
101
+ fileName: 'public_test.txt',
102
+ content: 'This is a public file'
103
+ })
104
+ });
105
+
106
+ const publicData = await publicResponse.json();
107
+ console.log('Public save response:', publicData);
108
+ console.log('βœ… Public save:', publicData.success ? 'SUCCESS' : 'FAILED');
109
+
110
+ // Summary
111
+ console.log('\n' + '='.repeat(50));
112
+ console.log('πŸ“Š TEST SUMMARY:');
113
+ console.log(` Session ID: ${sessionId}`);
114
+ console.log(` Files in session: ${getData.count || 0}`);
115
+ console.log(` Quiz detected: ${getData.files?.some(f => f.isQuiz) ? 'YES' : 'NO'}`);
116
+ console.log('='.repeat(50));
117
+
118
+ } catch (error) {
119
+ console.error('❌ Test failed with error:', error);
120
+ console.error('\nMake sure:');
121
+ console.error('1. Your Next.js server is running (npm run dev)');
122
+ console.error('2. The API endpoint is accessible');
123
+ console.error('3. The /tmp directory is writable');
124
+ }
125
+ }
126
+
127
+ // Run the test
128
+ testAPI();
test-mcp-local.js ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // test-mcp-local.js - Test MCP server locally
2
+ // This simulates what Claude would do
3
+
4
+ import { spawn } from 'child_process';
5
+ import readline from 'readline';
6
+
7
+ console.log('πŸš€ Starting MCP Server Test...\n');
8
+
9
+ // Start the MCP server
10
+ const mcp = spawn('node', ['mcp-server.js'], {
11
+ env: {
12
+ ...process.env,
13
+ REUBENOS_URL: 'https://huggingface.co/spaces/MCP-1st-Birthday/Reuben_OS'
14
+ }
15
+ });
16
+
17
+ const rl = readline.createInterface({
18
+ input: process.stdin,
19
+ output: process.stdout
20
+ });
21
+
22
+ // Handle MCP output
23
+ mcp.stderr.on('data', (data) => {
24
+ console.log('MCP:', data.toString());
25
+ });
26
+
27
+ mcp.stdout.on('data', (data) => {
28
+ console.log('MCP Output:', data.toString());
29
+ });
30
+
31
+ // Send test commands
32
+ async function testCommands() {
33
+ const sessionId = 'session_1763722877048_527d6bb8b7473568';
34
+
35
+ // Test manage_files tool
36
+ const testFileCommand = {
37
+ jsonrpc: '2.0',
38
+ id: 1,
39
+ method: 'tools/call',
40
+ params: {
41
+ name: 'manage_files',
42
+ arguments: {
43
+ sessionId: sessionId,
44
+ action: 'save',
45
+ fileName: 'test_from_mcp.txt',
46
+ content: 'This is a test from the MCP server'
47
+ }
48
+ }
49
+ };
50
+
51
+ console.log('πŸ“ Testing file save...');
52
+ console.log('Command:', JSON.stringify(testFileCommand, null, 2));
53
+
54
+ // Note: This would need proper JSON-RPC communication
55
+ // For now, this just shows what would be sent
56
+ }
57
+
58
+ console.log('πŸ“Œ Session ID for testing:', 'session_1763722877048_527d6bb8b7473568');
59
+ console.log('\nTo test manually:');
60
+ console.log('1. Restart Claude Desktop');
61
+ console.log('2. Tell Claude: "My session is session_1763722877048_527d6bb8b7473568"');
62
+ console.log('3. Ask Claude to save a file or deploy a quiz\n');
63
+
64
+ rl.question('Press Enter to exit...', () => {
65
+ mcp.kill();
66
+ rl.close();
67
+ });
68
+
69
+ testCommands();