feat: Enhance Keep-Alive configuration handling (#455)

This commit is contained in:
samanhappy
2025-11-30 09:59:48 +08:00
committed by GitHub
parent 063b081297
commit 8770b9ccfe
14 changed files with 234 additions and 175 deletions

View File

@@ -0,0 +1,73 @@
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { ServerInfo, ServerConfig } from '../types/index.js';
export interface KeepAliveOptions {
enabled?: boolean;
intervalMs?: number;
}
/**
* Set up keep-alive ping for MCP client connections (SSE or Streamable HTTP).
* Keepalive is controlled per-server via `serverConfig.enableKeepAlive` (default off).
*/
export const setupClientKeepAlive = async (
serverInfo: ServerInfo,
serverConfig: ServerConfig,
): Promise<void> => {
// Only set up keep-alive for SSE or Streamable HTTP client transports
const isSSE = serverInfo.transport instanceof SSEClientTransport;
const isStreamableHttp = serverInfo.transport instanceof StreamableHTTPClientTransport;
if (!isSSE && !isStreamableHttp) {
return;
}
const enabled = serverConfig.enableKeepAlive === true;
if (!enabled) {
// Ensure any previous timer is cleared
if (serverInfo.keepAliveIntervalId) {
clearInterval(serverInfo.keepAliveIntervalId as NodeJS.Timeout);
serverInfo.keepAliveIntervalId = undefined;
}
return;
}
// Clear any existing interval first
if (serverInfo.keepAliveIntervalId) {
clearInterval(serverInfo.keepAliveIntervalId as NodeJS.Timeout);
}
// Default interval: 60 seconds
const interval = serverConfig.keepAliveInterval || 60000;
serverInfo.keepAliveIntervalId = setInterval(async () => {
try {
if (serverInfo.client && serverInfo.status === 'connected') {
// Use client.ping() if available, otherwise fallback to listTools
if (typeof (serverInfo.client as any).ping === 'function') {
await (serverInfo.client as any).ping();
console.log(`Keep-alive ping successful for server: ${serverInfo.name}`);
} else {
await serverInfo.client.listTools({ timeout: 5000 }).catch(() => void 0);
}
}
} catch (error) {
console.warn(`Keep-alive ping failed for server ${serverInfo.name}:`, error);
}
}, interval);
console.log(
`Keep-alive enabled for server ${serverInfo.name} at ${Math.round(interval / 1000)}s interval`,
);
};
/**
* Clear keep-alive timer for a server.
*/
export const clearClientKeepAlive = (serverInfo: ServerInfo): void => {
if (serverInfo.keepAliveIntervalId) {
clearInterval(serverInfo.keepAliveIntervalId as NodeJS.Timeout);
serverInfo.keepAliveIntervalId = undefined;
console.log(`Cleared keep-alive interval for server: ${serverInfo.name}`);
}
};