@pluggedin/pluggedin-mcp-proxy
Version:
Unified MCP proxy that aggregates all your MCP servers (STDIO, SSE, Streamable HTTP) into one powerful interface. Access any tool through a single connection, search across unified documents with built-in RAG, and receive notifications from any model. Tes
96 lines (95 loc) • 4.43 kB
JavaScript
import axios from "axios";
import { getDefaultEnvironment, getPluggedinMCPApiBaseUrl, getPluggedinMCPApiKey, } from "./utils.js";
import { debugLog, debugError } from "./debug-log.js";
let _mcpServersCache = null;
let _mcpServersCacheTimestamp = 0;
const CACHE_TTL_MS = 1000; // 1 second cache TTL
// Removed logger
export async function getMcpServers(forceRefresh = false) {
const currentTime = Date.now();
const cacheAge = currentTime - _mcpServersCacheTimestamp;
// Use cache if it exists, is not null, and either:
// 1. forceRefresh is false, or
// 2. forceRefresh is true but cache is less than 1 second old
if (_mcpServersCache !== null && (!forceRefresh || cacheAge < CACHE_TTL_MS)) {
return _mcpServersCache;
}
try {
const apiKey = getPluggedinMCPApiKey();
const apiBaseUrl = getPluggedinMCPApiBaseUrl();
if (!apiKey || !apiBaseUrl) { // Also check apiBaseUrl
// logger.error( // Removed logging
// "PLUGGEDIN_API_KEY or PLUGGEDIN_API_BASE_URL is not set. Cannot fetch MCP servers."
// );
// Return the last known cache if available, otherwise empty object
return _mcpServersCache || {};
}
const headers = { Authorization: `Bearer ${apiKey}` };
const response = await axios.get(`${apiBaseUrl}/api/mcp-servers`, {
headers,
});
const data = response.data;
const serverDict = {};
for (const serverParams of data) {
const params = {
...serverParams,
type: serverParams.type || "STDIO",
};
// Process based on server type
if (params.type === "STDIO") {
if ("args" in params && !params.args) {
params.args = undefined;
}
params.env = {
...getDefaultEnvironment(),
...(params.env || {}),
};
}
else if (params.type === "SSE") {
// For SSE servers, ensure url is present
if (!params.url) {
// logger.warn( // Removed logging
// `SSE server ${params.uuid} (${params.name}) is missing url field, skipping`
// );
continue;
}
}
else if (params.type === "STREAMABLE_HTTP") {
// Map streamableHTTPOptions to direct fields for backward compatibility
// Merge headers for backward compatibility, streamableHTTPOptions.headers takes precedence
params.headers = {
...(params.headers || {}),
...(params.streamableHTTPOptions?.headers || {}),
};
// For sessionId, streamableHTTPOptions.sessionId takes precedence if present
params.sessionId = params.streamableHTTPOptions?.sessionId || params.sessionId;
// Log if headers or sessionId are present
if ((params.headers && Object.keys(params.headers).length > 0) || params.sessionId) {
debugLog(`[MCP] StreamableHTTP server ${params.name}: headers=${Object.keys(params.headers || {}).length}, sessionId=${!!params.sessionId}`);
}
// Ensure url is present
if (!params.url) {
debugError(`StreamableHTTP server ${params.uuid} (${params.name}) is missing url field, skipping`);
continue;
}
}
const uuid = params.uuid;
if (uuid) {
serverDict[uuid] = params;
}
}
_mcpServersCache = serverDict;
_mcpServersCacheTimestamp = currentTime;
// logger.debug(`Fetched and cached ${Object.keys(serverDict).length} MCP server configurations.`); // Removed logging
return serverDict;
}
catch (error) { // Add type to error
// logger.error("Failed to fetch MCP servers from API:", error.message || error); // Removed logging
// Return the last known cache if available on error, otherwise empty object
if (_mcpServersCache !== null) {
// logger.warn("Returning stale MCP server cache due to fetch error."); // Removed logging
return _mcpServersCache;
}
return {};
}
}