Update server.js
Browse files
server.js
CHANGED
|
@@ -6,30 +6,29 @@ const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch
|
|
| 6 |
const app = express();
|
| 7 |
const PORT = process.env.PORT || 7860;
|
| 8 |
|
| 9 |
-
// --- 1.
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
app.set('trust proxy', 1);
|
| 13 |
|
| 14 |
-
// --- 2.
|
| 15 |
const corsOptions = {
|
| 16 |
origin: '*',
|
| 17 |
methods: ['GET', 'POST', 'OPTIONS'],
|
| 18 |
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
|
| 19 |
};
|
| 20 |
app.use(cors(corsOptions));
|
| 21 |
-
app.options(/.*/, cors(corsOptions)); //
|
| 22 |
-
app.use(express.json({ limit: '10mb' }));
|
| 23 |
|
| 24 |
-
//
|
| 25 |
app.use((req, res, next) => {
|
| 26 |
-
|
|
|
|
| 27 |
next();
|
| 28 |
});
|
| 29 |
|
| 30 |
-
// ---
|
| 31 |
app.get('/sse', (req, res) => {
|
| 32 |
-
console.log("[SSE]
|
| 33 |
|
| 34 |
res.writeHead(200, {
|
| 35 |
'Content-Type': 'text/event-stream',
|
|
@@ -39,21 +38,20 @@ app.get('/sse', (req, res) => {
|
|
| 39 |
'Access-Control-Allow-Origin': '*'
|
| 40 |
});
|
| 41 |
|
| 42 |
-
//
|
| 43 |
-
// With 'trust proxy', req.protocol should be 'https'
|
| 44 |
const protocol = req.protocol === 'http' ? 'https' : req.protocol;
|
| 45 |
const host = req.get('host');
|
| 46 |
const messageEndpoint = `${protocol}://${host}/messages`;
|
| 47 |
|
| 48 |
-
console.log(`[SSE]
|
| 49 |
|
| 50 |
// 1. Send Endpoint Event
|
| 51 |
res.write(`event: endpoint\ndata: ${messageEndpoint}\n\n`);
|
| 52 |
|
| 53 |
-
// 2. Send Padding (
|
| 54 |
res.write(`: ${" ".repeat(4096)}\n\n`);
|
| 55 |
|
| 56 |
-
// 3.
|
| 57 |
const interval = setInterval(() => {
|
| 58 |
res.write(`: ping\n\n`);
|
| 59 |
}, 10000);
|
|
@@ -64,38 +62,31 @@ app.get('/sse', (req, res) => {
|
|
| 64 |
});
|
| 65 |
});
|
| 66 |
|
| 67 |
-
// ---
|
| 68 |
app.post('/messages', async (req, res) => {
|
| 69 |
try {
|
| 70 |
const body = req.body;
|
| 71 |
-
const requestId = body.id;
|
| 72 |
|
| 73 |
console.log(`[MESSAGES] Method: ${body.method} | ID: ${requestId}`);
|
| 74 |
|
| 75 |
// A. Initialize
|
| 76 |
if (body.method === 'initialize') {
|
| 77 |
-
|
|
|
|
| 78 |
jsonrpc: "2.0",
|
| 79 |
id: requestId,
|
| 80 |
result: {
|
| 81 |
protocolVersion: "2024-11-05",
|
| 82 |
-
capabilities: {
|
| 83 |
-
// Return empty objects for all capabilities to be safe
|
| 84 |
-
tools: {},
|
| 85 |
-
prompts: {},
|
| 86 |
-
resources: {},
|
| 87 |
-
logging: {}
|
| 88 |
-
},
|
| 89 |
serverInfo: { name: "github-mcp-hf", version: "1.0.0" }
|
| 90 |
}
|
| 91 |
-
};
|
| 92 |
-
console.log("[MESSAGES] Sending Init Response");
|
| 93 |
-
return res.json(response);
|
| 94 |
}
|
| 95 |
|
| 96 |
// B. List Tools
|
| 97 |
if (body.method === 'tools/list') {
|
| 98 |
-
console.log("[MESSAGES]
|
| 99 |
return res.json({
|
| 100 |
jsonrpc: "2.0",
|
| 101 |
id: requestId,
|
|
@@ -160,11 +151,9 @@ app.post('/messages', async (req, res) => {
|
|
| 160 |
});
|
| 161 |
}
|
| 162 |
}
|
| 163 |
-
|
| 164 |
-
// D. Notifications
|
| 165 |
if (body.method === 'notifications/initialized') {
|
| 166 |
-
|
| 167 |
-
return res.json({ result: true }); // Ack
|
| 168 |
}
|
| 169 |
|
| 170 |
res.status(404).json({ error: "Method not found" });
|
|
@@ -175,16 +164,19 @@ app.post('/messages', async (req, res) => {
|
|
| 175 |
}
|
| 176 |
});
|
| 177 |
|
| 178 |
-
// ---
|
|
|
|
| 179 |
app.use((req, res) => {
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
|
|
|
|
|
|
| 185 |
});
|
| 186 |
|
| 187 |
-
// ---
|
| 188 |
app.listen(PORT, '0.0.0.0', () => {
|
| 189 |
console.log(`Server running on port ${PORT}`);
|
| 190 |
});
|
|
|
|
| 6 |
const app = express();
|
| 7 |
const PORT = process.env.PORT || 7860;
|
| 8 |
|
| 9 |
+
// --- 1. CONFIGURATION ---
|
| 10 |
+
app.set('trust proxy', 1); // Required for Hugging Face Spaces
|
| 11 |
+
app.use(express.json({ limit: '10mb' }));
|
|
|
|
| 12 |
|
| 13 |
+
// --- 2. CORS (Strict & Global) ---
|
| 14 |
const corsOptions = {
|
| 15 |
origin: '*',
|
| 16 |
methods: ['GET', 'POST', 'OPTIONS'],
|
| 17 |
allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],
|
| 18 |
};
|
| 19 |
app.use(cors(corsOptions));
|
| 20 |
+
app.options(/.*/, cors(corsOptions)); // Handle Preflight for all routes
|
|
|
|
| 21 |
|
| 22 |
+
// --- 3. LOGGING ---
|
| 23 |
app.use((req, res, next) => {
|
| 24 |
+
// Log request to debug timing
|
| 25 |
+
console.log(`[${new Date().toISOString()}] ${req.method} ${req.originalUrl}`);
|
| 26 |
next();
|
| 27 |
});
|
| 28 |
|
| 29 |
+
// --- 4. SSE ENDPOINT ---
|
| 30 |
app.get('/sse', (req, res) => {
|
| 31 |
+
console.log("[SSE] Connection Initiated");
|
| 32 |
|
| 33 |
res.writeHead(200, {
|
| 34 |
'Content-Type': 'text/event-stream',
|
|
|
|
| 38 |
'Access-Control-Allow-Origin': '*'
|
| 39 |
});
|
| 40 |
|
| 41 |
+
// Calculate external endpoint
|
|
|
|
| 42 |
const protocol = req.protocol === 'http' ? 'https' : req.protocol;
|
| 43 |
const host = req.get('host');
|
| 44 |
const messageEndpoint = `${protocol}://${host}/messages`;
|
| 45 |
|
| 46 |
+
console.log(`[SSE] Endpoint: ${messageEndpoint}`);
|
| 47 |
|
| 48 |
// 1. Send Endpoint Event
|
| 49 |
res.write(`event: endpoint\ndata: ${messageEndpoint}\n\n`);
|
| 50 |
|
| 51 |
+
// 2. Send Padding (Keep buffer flush)
|
| 52 |
res.write(`: ${" ".repeat(4096)}\n\n`);
|
| 53 |
|
| 54 |
+
// 3. Keep-Alive Loop
|
| 55 |
const interval = setInterval(() => {
|
| 56 |
res.write(`: ping\n\n`);
|
| 57 |
}, 10000);
|
|
|
|
| 62 |
});
|
| 63 |
});
|
| 64 |
|
| 65 |
+
// --- 5. MESSAGES ENDPOINT ---
|
| 66 |
app.post('/messages', async (req, res) => {
|
| 67 |
try {
|
| 68 |
const body = req.body;
|
| 69 |
+
const requestId = body.id;
|
| 70 |
|
| 71 |
console.log(`[MESSAGES] Method: ${body.method} | ID: ${requestId}`);
|
| 72 |
|
| 73 |
// A. Initialize
|
| 74 |
if (body.method === 'initialize') {
|
| 75 |
+
console.log("[MESSAGES] Sending Init Response");
|
| 76 |
+
return res.json({
|
| 77 |
jsonrpc: "2.0",
|
| 78 |
id: requestId,
|
| 79 |
result: {
|
| 80 |
protocolVersion: "2024-11-05",
|
| 81 |
+
capabilities: { tools: {}, prompts: {}, resources: {} },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
serverInfo: { name: "github-mcp-hf", version: "1.0.0" }
|
| 83 |
}
|
| 84 |
+
});
|
|
|
|
|
|
|
| 85 |
}
|
| 86 |
|
| 87 |
// B. List Tools
|
| 88 |
if (body.method === 'tools/list') {
|
| 89 |
+
console.log("[MESSAGES] Sending Tool List");
|
| 90 |
return res.json({
|
| 91 |
jsonrpc: "2.0",
|
| 92 |
id: requestId,
|
|
|
|
| 151 |
});
|
| 152 |
}
|
| 153 |
}
|
| 154 |
+
|
|
|
|
| 155 |
if (body.method === 'notifications/initialized') {
|
| 156 |
+
return res.json({ result: true });
|
|
|
|
| 157 |
}
|
| 158 |
|
| 159 |
res.status(404).json({ error: "Method not found" });
|
|
|
|
| 164 |
}
|
| 165 |
});
|
| 166 |
|
| 167 |
+
// --- 6. JSON FALLBACK (The Fix) ---
|
| 168 |
+
// We handle ALL other requests by returning JSON, never Text/HTML.
|
| 169 |
app.use((req, res) => {
|
| 170 |
+
console.log(`[FALLBACK] Handling ${req.method} ${req.path}`);
|
| 171 |
+
// Return valid JSON so ChatUI parsers don't crash
|
| 172 |
+
res.status(200).json({
|
| 173 |
+
status: "active",
|
| 174 |
+
message: "MCP Server Running",
|
| 175 |
+
path: req.path
|
| 176 |
+
});
|
| 177 |
});
|
| 178 |
|
| 179 |
+
// --- 7. STARTUP ---
|
| 180 |
app.listen(PORT, '0.0.0.0', () => {
|
| 181 |
console.log(`Server running on port ${PORT}`);
|
| 182 |
});
|