Skip to main content
Glama
index.ts4.87 kB
import 'dotenv/config' import express from 'express' import type { Request, Response } from 'express' import { DependencyContainer } from './server/dependency-container.js' import { collectSystemMetrics } from './utils/monitoring.js' import { CapabilityAggregator } from './modules/capability-aggregator.js' import { createMcpServer } from './mcp-server.js' export interface RunningServer { name: string version: string container: DependencyContainer stop: () => Promise<void> } function isNode(): boolean { return Boolean((globalThis as any)?.process?.versions?.node) } export async function createServer(startHttp = true): Promise<RunningServer> { const version = (globalThis as any)?.process?.env?.APP_VERSION ?? '0.1.0' const container = new DependencyContainer() await container.initialize() const server: RunningServer = { name: 'master-mcp-server', version, container, stop: async () => { try { container.configManager.stop() await container.master.unloadAll() } catch { // ignore } }, } if (isNode() && startHttp) { await startNodeHttp(container) } // Graceful shutdown (Node only) if (isNode()) { const onSig = async () => { await server.stop() ;(process as any).exit?.(0) } process.on('SIGINT', onSig) process.on('SIGTERM', onSig) } return server } async function startNodeHttp(container: DependencyContainer): Promise<void> { const app = express() app.use(express.json()) // Serve static assets for OAuth pages // eslint-disable-next-line @typescript-eslint/no-var-requires const expressStatic = (express as any).static if (expressStatic) app.use('/static', expressStatic('static')) const getToken = (req: Request): string | undefined => { const h = req.headers['authorization'] || req.headers['Authorization'] if (typeof h === 'string' && h.toLowerCase().startsWith('bearer ')) return h.slice(7) return undefined } app.get('/health', (_req, res) => res.json({ ok: true })) app.get('/metrics', (_req, res) => { try { res.json({ ok: true, system: collectSystemMetrics() }) } catch { res.json({ ok: true }) } }) // Mount OAuth endpoints using the master server's controller try { container.master.getOAuthFlowController().registerExpress(app) } catch { // If not available yet, ignore; will be mounted on demand if needed } app.get('/capabilities', (_req, res) => { const agg = new CapabilityAggregator() const caps = agg.aggregate(Array.from(container.master.getRouter().getServers().values())) res.json(caps) }) // Create the MCP server with HTTP streaming transport const { handleRequest } = await createMcpServer(container) // Register MCP endpoints app.post('/mcp', handleRequest) app.get('/mcp', handleRequest) app.delete('/mcp', handleRequest) // Keep the existing endpoints for backward compatibility app.post('/mcp/tools/list', async (_req: Request, res: Response) => { const handler = container.master.handler const result = await handler.handleListTools({ type: 'list_tools' }) res.json(result) }) app.post('/mcp/tools/call', async (req: Request, res: Response) => { const token = getToken(req) const handler = new (container.master.handler.constructor as any)({ aggregator: container.aggregator, router: container.master.getRouter(), getClientToken: () => token, }) as typeof container.master.handler const result = await handler.handleCallTool({ name: req.body?.name, arguments: req.body?.arguments ?? {} }) res.json(result) }) app.post('/mcp/resources/list', async (_req: Request, res: Response) => { const handler = container.master.handler const result = await handler.handleListResources({ type: 'list_resources' }) res.json(result) }) app.post('/mcp/resources/read', async (req: Request, res: Response) => { const token = getToken(req) const handler = new (container.master.handler.constructor as any)({ aggregator: container.aggregator, router: container.master.getRouter(), getClientToken: () => token, }) as typeof container.master.handler const result = await handler.handleReadResource({ uri: req.body?.uri }) res.json(result) }) const port = container.getConfig().hosting.port ?? 3000 await new Promise<void>((resolve) => { app.listen(port, () => { // eslint-disable-next-line no-console console.log(`Master MCP listening on http://localhost:${port}`) resolve() }) }) } export default createServer // If this file is being run directly (not imported), start the server if (import.meta.url === `file://${process.argv[1]}`) { createServer().catch((err) => { console.error('Failed to start server:', err) process.exit(1) }) }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Jakedismo/master-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server