Spaces:
Running
Running
testing mcp
Browse files- .claude/settings.local.json +3 -1
- DEPLOYMENT_FIX.md +99 -0
- claude-desktop-config.json +11 -0
- mcp-server.js +8 -6
- pages/api/mcp-handler.js +39 -9
- test-api.js +128 -0
- test-mcp-local.js +69 -0
.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 || '
|
| 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
|
| 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
|
| 6 |
-
async function
|
|
|
|
| 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
|
| 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 |
-
//
|
|
|
|
|
|
|
|
|
|
| 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();
|