Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion gitlab-client-pool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,23 @@ export class GitLabClientPool {
}
return this.clients.get(defaultUrl)!;
}
}

/**
* Destroy all pooled agents and clear pool state.
* This should be called on graceful shutdown so sockets are closed
* and the process can exit cleanly.
*/
public closeAll(): void {
for (const [, agents] of this.clients) {
const destroyIfSupported = (agent: unknown) => {
if (agent && typeof (agent as { destroy?: () => void }).destroy === "function") {
(agent as { destroy: () => void }).destroy();
}
};

destroyIfSupported(agents.httpAgent);
destroyIfSupported(agents.httpsAgent);
}
this.clients.clear();
}
}
33 changes: 32 additions & 1 deletion index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7341,6 +7341,10 @@ function determineTransportMode(): TransportMode {
async function startStdioServer(): Promise<void> {
const serverInstance = createServer();
const transport = new StdioServerTransport();
transport.onclose = () => {
logger.info("Stdio transport closed, releasing client pool");
clientPool.closeAll();
};
await serverInstance.connect(transport);
}

Expand All @@ -7350,6 +7354,7 @@ async function startStdioServer(): Promise<void> {
async function startSSEServer(): Promise<void> {
const app = express();
const transports: { [sessionId: string]: SSEServerTransport } = {};
let shuttingDown = false;

app.get("/sse", async (_: Request, res: Response) => {
const serverInstance = createServer();
Expand Down Expand Up @@ -7379,12 +7384,37 @@ async function startSSEServer(): Promise<void> {
});
});

app.listen(Number(PORT), HOST, () => {
const httpServer = app.listen(Number(PORT), HOST, () => {
logger.info(`GitLab MCP Server running with SSE transport`);
const colorGreen = "\x1b[32m";
const colorReset = "\x1b[0m";
logger.info(`${colorGreen}Endpoint: http://${HOST}:${PORT}/sse${colorReset}`);
});

const shutdown = async (signal: string) => {
if (shuttingDown) return;
shuttingDown = true;
logger.info(`${signal} received, shutting down SSE server...`);
httpServer.close(() => logger.info("SSE HTTP server closed"));
await Promise.allSettled(
Object.values(transports).map(async transport => {
try {
await transport.close();
} catch (error) {
logger.error("Error closing SSE transport:", error);
}
})
);
clientPool.closeAll();
process.exit(0);
};

process.on("SIGTERM", () => {
void shutdown("SIGTERM");
});
process.on("SIGINT", () => {
void shutdown("SIGINT");
});
}

/**
Expand Down Expand Up @@ -7790,6 +7820,7 @@ async function startStreamableHTTPServer(): Promise<void> {
clearAuthTimeout(sessionId);
});

clientPool.closeAll();
logger.info("Graceful shutdown complete");
process.exit(0);
};
Expand Down
Loading