feat: implement dynamic package versioning and refactor MCP server initialization (#104)

This commit is contained in:
samanhappy
2025-05-18 20:07:01 +08:00
committed by GitHub
parent ae3fe1c6f1
commit f46e2c22fc
6 changed files with 57 additions and 12 deletions

View File

@@ -40,7 +40,11 @@ const Header: React.FC<HeaderProps> = ({ onToggleSidebar }) => {
{/* Theme Switch and Version */}
<div className="flex items-center space-x-4">
<span className="text-sm text-gray-500 dark:text-gray-400">{import.meta.env.PACKAGE_VERSION}</span>
<span className="text-sm text-gray-500 dark:text-gray-400">
{import.meta.env.PACKAGE_VERSION === 'dev'
? import.meta.env.PACKAGE_VERSION
: `v${import.meta.env.PACKAGE_VERSION}`}
</span>
<a
href="https://github.com/samanhappy/mcphub"
target="_blank"

View File

@@ -2,6 +2,7 @@ import dotenv from 'dotenv';
import fs from 'fs';
import { McpSettings } from '../types/index.js';
import { getConfigFilePath } from '../utils/path.js';
import { getPackageVersion } from '../utils/version.js';
dotenv.config();
@@ -10,7 +11,7 @@ const defaultConfig = {
initTimeout: process.env.INIT_TIMEOUT || 300000,
timeout: process.env.REQUEST_TIMEOUT || 60000,
mcpHubName: 'mcphub',
mcpHubVersion: '0.0.1',
mcpHubVersion: getPackageVersion(),
};
export const getSettingsPath = (): string => {

View File

@@ -3,7 +3,7 @@ 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 { initUpstreamServers } from './services/mcpService.js';
import { initMiddlewares } from './middlewares/index.js';
import { initRoutes } from './routes/index.js';
import {
@@ -37,7 +37,7 @@ export class AppServer {
initRoutes(this.app);
console.log('Server initialized successfully');
initMcpServer(config.mcpHubName, config.mcpHubVersion)
initUpstreamServers()
.then(() => {
console.log('MCP server initialized successfully');
this.app.get('/sse/:group?', (req, res) => handleSseConnection(req, res));

View File

@@ -12,17 +12,18 @@ import { getServersInGroup } from './groupService.js';
const servers: { [sessionId: string]: Server } = {};
export const initMcpServer = async (name: string, version: string): Promise<void> => {
export const initUpstreamServers = async (): Promise<void> => {
await registerAllTools(true);
};
export const getMcpServer = (sessionId?: string): Server => {
export const getMcpServer = (sessionId?: string, group?: string): Server => {
if (!sessionId) {
return createMcpServer(config.mcpHubName, config.mcpHubVersion);
return createMcpServer(config.mcpHubName, config.mcpHubVersion, group);
}
if (!servers[sessionId]) {
const server = createMcpServer(config.mcpHubName, config.mcpHubVersion);
const serverGroup = group || getGroup(sessionId);
const server = createMcpServer(config.mcpHubName, config.mcpHubVersion, serverGroup);
servers[sessionId] = server;
} else {
console.log(`MCP server already exists for sessionId: ${sessionId}`);
@@ -417,8 +418,24 @@ const handleCallToolRequest = async (request: any, extra: any) => {
};
// Create McpServer instance
export const createMcpServer = (name: string, version: string): Server => {
const server = new Server({ name, version }, { capabilities: { tools: {} } });
export const createMcpServer = (name: string, version: string, group?: string): Server => {
// Determine server name based on routing type
let serverName = name;
if (group) {
// Check if it's a group or a single server
const serversInGroup = getServersInGroup(group);
if (!serversInGroup || serversInGroup.length === 0) {
// Single server routing
serverName = `${name}_${group}`;
} else {
// Group routing
serverName = `${name}_${group}_group`;
}
}
// If no group, use default name (global routing)
const server = new Server({ name: serverName, version }, { capabilities: { tools: {} } });
server.setRequestHandler(ListToolsRequestSchema, handleListToolsRequest);
server.setRequestHandler(CallToolRequestSchema, handleCallToolRequest);
return server;

View File

@@ -70,7 +70,7 @@ export const handleSseConnection = async (req: Request, res: Response): Promise<
console.log(
`New SSE connection established: ${transport.sessionId} with group: ${group || 'global'}`,
);
await getMcpServer(transport.sessionId).connect(transport);
await getMcpServer(transport.sessionId, group).connect(transport);
};
export const handleSseMessage = async (req: Request, res: Response): Promise<void> => {
@@ -135,7 +135,7 @@ export const handleMcpPostRequest = async (req: Request, res: Response): Promise
};
console.log(`MCP connection established: ${transport.sessionId}`);
await getMcpServer(transport.sessionId).connect(transport);
await getMcpServer(transport.sessionId, group).connect(transport);
} else {
res.status(400).json({
jsonrpc: '2.0',

23
src/utils/version.ts Normal file
View File

@@ -0,0 +1,23 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
// Get the directory name in ESM
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* Gets the package version from package.json
* @returns The version string from package.json, or 'dev' if not found
*/
export const getPackageVersion = (): string => {
try {
const packageJsonPath = path.resolve(__dirname, '../../package.json');
const packageJsonContent = fs.readFileSync(packageJsonPath, 'utf8');
const packageJson = JSON.parse(packageJsonContent);
return packageJson.version || 'dev';
} catch (error) {
console.error('Error reading package version:', error);
return 'dev';
}
};