@upstash/context7-mcp
Version:
MCP server for Context7
64 lines (63 loc) • 2.08 kB
JavaScript
const DEFAULT_CLOSE_TIMEOUT_MS = 5_000;
const DEFAULT_FLUSH_TIMEOUT_MS = 5_000;
async function withTimeout(operation, timeoutMs, description) {
let timeout;
try {
await Promise.race([
operation(),
new Promise((_resolve, reject) => {
timeout = setTimeout(() => reject(new Error(`${description} exceeded ${timeoutMs}ms`)), timeoutMs);
}),
]);
}
finally {
if (timeout)
clearTimeout(timeout);
}
}
/**
* Coordinates one bounded, idempotent process shutdown for HTTP and stdio.
* Passing an input lifecycle additionally treats stdio EOF as termination.
*/
export function installProcessShutdown(handle, options = {}) {
const signals = options.signals ?? process;
const exit = options.exit ?? ((code) => process.exit(code));
const closeTimeoutMs = options.closeTimeoutMs ?? DEFAULT_CLOSE_TIMEOUT_MS;
const flushTimeoutMs = options.flushTimeoutMs ?? DEFAULT_FLUSH_TIMEOUT_MS;
let shutdownPromise;
const reportError = (error) => {
try {
options.onerror?.(error);
}
catch {
// A reporting callback must not prevent shutdown.
}
};
const shutdown = () => {
shutdownPromise ??= (async () => {
let exitCode = 0;
try {
await withTimeout(() => handle.close(), closeTimeoutMs, "Server close");
}
catch (error) {
exitCode = 1;
reportError(error);
}
try {
if (options.flush) {
await withTimeout(options.flush, flushTimeoutMs, "OpenTelemetry flush");
}
}
catch (error) {
reportError(error);
}
exit(exitCode);
})();
};
options.input?.once("end", shutdown);
options.input?.once("close", shutdown);
signals.once("SIGHUP", shutdown);
signals.once("SIGINT", shutdown);
signals.once("SIGTERM", shutdown);
return shutdown;
}