Skip to main content
Glama
url-resolver.ts3.07 kB
import { existsSync, readFileSync } from 'fs'; import { resolve, extname } from 'path'; import { createServer } from 'http'; export interface ResolvedUrl { url: string; isLocal: boolean; cleanup?: () => Promise<void>; } const TEMP_SERVER_PORT_START = 30000; let tempServerPort = TEMP_SERVER_PORT_START; function isUrl(input: string): boolean { try { const url = new URL(input); return url.protocol === 'http:' || url.protocol === 'https:'; } catch { return false; } } function isFileProtocol(input: string): boolean { try { const url = new URL(input); return url.protocol === 'file:'; } catch { return false; } } function isLocalhost(input: string): boolean { try { const url = new URL(input); return url.hostname === 'localhost' || url.hostname === '127.0.0.1' || url.hostname === '::1'; } catch { return false; } } function isFilePath(input: string): boolean { if (isUrl(input) || isFileProtocol(input)) { return false; } const resolved = resolve(input); return existsSync(resolved) && (extname(resolved) === '.html' || extname(resolved) === '.htm'); } export async function resolveUrl(input: string): Promise<ResolvedUrl> { if (isUrl(input)) { return { url: input, isLocal: isLocalhost(input), }; } if (isFileProtocol(input)) { return { url: input, isLocal: true, }; } if (isFilePath(input)) { const filePath = resolve(input); const fileContent = readFileSync(filePath, 'utf-8'); const server = await createTempServer(fileContent); const url = `http://localhost:${server.port}`; return { url, isLocal: true, cleanup: async () => { await new Promise<void>((resolve) => { server.server.close(() => resolve()); }); }, }; } throw new Error(`Invalid input: "${input}" is not a valid URL, file:// URL, or local file path`); } async function createTempServer(htmlContent: string): Promise<{ server: ReturnType<typeof createServer>; port: number }> { return new Promise((resolve, reject) => { let attempts = 0; const maxAttempts = 10; const tryCreateServer = (port: number) => { const server = createServer((req, res) => { if (req.url === '/' || req.url === '/index.html') { res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' }); res.end(htmlContent); } else { res.writeHead(404); res.end('Not found'); } }); server.listen(port, '127.0.0.1', () => { resolve({ server, port }); }); server.on('error', (err: NodeJS.ErrnoException) => { if (err.code === 'EADDRINUSE') { attempts++; if (attempts < maxAttempts) { tryCreateServer(port + 1); } else { reject(new Error('Could not find available port for temporary server')); } } else { reject(err); } }); }; const port = tempServerPort++; tryCreateServer(port); }); }

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/Duds/accessibility-mcp'

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