mirror of
https://github.com/samanhappy/mcphub.git
synced 2026-01-02 04:39:23 -05:00
feat: enhance configuration file handling and dynamic frontend path resolution (#40)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
132
src/server.ts
132
src/server.ts
@@ -1,6 +1,8 @@
|
||||
import express from 'express';
|
||||
import config from './config/index.js';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fs from 'fs';
|
||||
import { initMcpServer } from './services/mcpService.js';
|
||||
import { initMiddlewares } from './middlewares/index.js';
|
||||
import { initRoutes } from './routes/index.js';
|
||||
@@ -13,9 +15,14 @@ import {
|
||||
import { migrateUserData } from './utils/migration.js';
|
||||
import { initializeDefaultUser } from './models/User.js';
|
||||
|
||||
// Get the directory name in ESM
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export class AppServer {
|
||||
private app: express.Application;
|
||||
private port: number | string;
|
||||
private frontendPath: string | null = null;
|
||||
|
||||
constructor() {
|
||||
this.app = express();
|
||||
@@ -48,9 +55,8 @@ export class AppServer {
|
||||
throw error;
|
||||
})
|
||||
.finally(() => {
|
||||
this.app.get('*', (_req, res) => {
|
||||
res.sendFile(path.join(process.cwd(), 'frontend', 'dist', 'index.html'));
|
||||
});
|
||||
// Find and serve frontend
|
||||
this.findAndServeFrontend();
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error initializing server:', error);
|
||||
@@ -58,15 +64,135 @@ export class AppServer {
|
||||
}
|
||||
}
|
||||
|
||||
private findAndServeFrontend(): void {
|
||||
// Find frontend path
|
||||
this.frontendPath = this.findFrontendDistPath();
|
||||
|
||||
if (this.frontendPath) {
|
||||
console.log(`Serving frontend from: ${this.frontendPath}`);
|
||||
this.app.use(express.static(this.frontendPath));
|
||||
|
||||
// Add the wildcard route for SPA
|
||||
if (fs.existsSync(path.join(this.frontendPath, 'index.html'))) {
|
||||
this.app.get('*', (_req, res) => {
|
||||
res.sendFile(path.join(this.frontendPath!, 'index.html'));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
console.warn('Frontend dist directory not found. Server will run without frontend.');
|
||||
this.app.get('/', (_req, res) => {
|
||||
res
|
||||
.status(404)
|
||||
.send('Frontend not found. MCPHub API is running, but the UI is not available.');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
start(): void {
|
||||
this.app.listen(this.port, () => {
|
||||
console.log(`Server is running on port ${this.port}`);
|
||||
if (this.frontendPath) {
|
||||
console.log(`Open http://localhost:${this.port} in your browser to access MCPHub UI`);
|
||||
} else {
|
||||
console.log(
|
||||
`MCPHub API is running on http://localhost:${this.port}, but the UI is not available`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getApp(): express.Application {
|
||||
return this.app;
|
||||
}
|
||||
|
||||
// Helper method to find frontend dist path in different environments
|
||||
private findFrontendDistPath(): string | null {
|
||||
// Debug flag for detailed logging
|
||||
const debug = process.env.DEBUG === 'true';
|
||||
|
||||
if (debug) {
|
||||
console.log('DEBUG: Current directory:', process.cwd());
|
||||
console.log('DEBUG: Script directory:', __dirname);
|
||||
}
|
||||
|
||||
// First, find the package root directory
|
||||
const packageRoot = this.findPackageRoot();
|
||||
|
||||
if (debug) {
|
||||
console.log('DEBUG: Using package root:', packageRoot);
|
||||
}
|
||||
|
||||
if (!packageRoot) {
|
||||
console.warn('Could not determine package root directory');
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for frontend dist in the standard location
|
||||
const frontendDistPath = path.join(packageRoot, 'frontend', 'dist');
|
||||
|
||||
if (debug) {
|
||||
console.log(`DEBUG: Checking frontend at: ${frontendDistPath}`);
|
||||
}
|
||||
|
||||
if (
|
||||
fs.existsSync(frontendDistPath) &&
|
||||
fs.existsSync(path.join(frontendDistPath, 'index.html'))
|
||||
) {
|
||||
return frontendDistPath;
|
||||
}
|
||||
|
||||
console.warn('Frontend distribution not found at', frontendDistPath);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Helper method to find the package root (where package.json is located)
|
||||
private findPackageRoot(): string | null {
|
||||
const debug = process.env.DEBUG === 'true';
|
||||
|
||||
// Possible locations for package.json
|
||||
const possibleRoots = [
|
||||
// Standard npm package location
|
||||
path.resolve(__dirname, '..', '..'),
|
||||
// Current working directory
|
||||
process.cwd(),
|
||||
// When running from dist directory
|
||||
path.resolve(__dirname, '..'),
|
||||
// When installed via npx
|
||||
path.resolve(__dirname, '..', '..', '..'),
|
||||
];
|
||||
|
||||
// Special handling for npx
|
||||
if (process.argv[1] && process.argv[1].includes('_npx')) {
|
||||
const npxDir = path.dirname(process.argv[1]);
|
||||
possibleRoots.unshift(path.resolve(npxDir, '..'));
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
console.log('DEBUG: Checking for package.json in:', possibleRoots);
|
||||
}
|
||||
|
||||
for (const root of possibleRoots) {
|
||||
const packageJsonPath = path.join(root, 'package.json');
|
||||
if (fs.existsSync(packageJsonPath)) {
|
||||
try {
|
||||
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
||||
if (pkg.name === 'mcphub' || pkg.name === '@samanhappy/mcphub') {
|
||||
if (debug) {
|
||||
console.log(`DEBUG: Found package.json at ${packageJsonPath}`);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
} catch (e) {
|
||||
if (debug) {
|
||||
console.error(`DEBUG: Failed to parse package.json at ${packageJsonPath}:`, e);
|
||||
}
|
||||
// Continue to the next potential root
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default AppServer;
|
||||
|
||||
Reference in New Issue
Block a user