feat: add request options configuration to server form (#171)

This commit is contained in:
samanhappy
2025-06-10 13:51:01 +08:00
committed by GitHub
parent 77f64b7b98
commit 4726f00a22
8 changed files with 160 additions and 46 deletions

View File

@@ -36,7 +36,7 @@ export const loadSettings = (): McpSettings => {
// Update cache
settingsCache = settings;
console.log(`Loaded settings from ${settingsPath}:`, settings);
console.log(`Loaded settings from ${settingsPath}`);
return settings;
} catch (error) {
console.error(`Failed to load settings from ${settingsPath}:`, error);

View File

@@ -1,37 +1,8 @@
import express, { Request, Response, NextFunction } from 'express';
import path from 'path';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import fs from 'fs';
import { auth } from './auth.js';
import { initializeDefaultUser } from '../models/User.js';
import config from '../config/index.js';
// Create __dirname equivalent for ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Try to find the correct frontend file path
const findFrontendPath = (): string => {
// First try development environment path
const devPath = path.join(dirname(__dirname), 'frontend', 'dist', 'index.html');
if (fs.existsSync(devPath)) {
return path.join(dirname(__dirname), 'frontend', 'dist');
}
// Try npm/npx installed path (remove /dist directory)
const npmPath = path.join(dirname(dirname(__dirname)), 'frontend', 'dist', 'index.html');
if (fs.existsSync(npmPath)) {
return path.join(dirname(dirname(__dirname)), 'frontend', 'dist');
}
// If none of the above paths exist, return the most reasonable default path and log a warning
console.warn('Warning: Could not locate frontend files. Using default path.');
return path.join(dirname(__dirname), 'frontend', 'dist');
};
const frontendPath = findFrontendPath();
export const errorHandler = (
err: Error,
_req: Request,
@@ -52,6 +23,7 @@ export const initMiddlewares = (app: express.Application): void => {
app.use((req, res, next) => {
const basePath = config.basePath;
// Only apply JSON parsing for API and auth routes, not for SSE or message endpoints
// TODO exclude sse responses by mcp endpoint
if (
req.path !== `${basePath}/sse` &&
!req.path.startsWith(`${basePath}/sse/`) &&

View File

@@ -218,14 +218,27 @@ export const initializeClientsFromSettings = (isInit: boolean): ServerInfo[] =>
},
},
);
const timeout = isInit ? Number(config.initTimeout) : Number(config.timeout);
const initRequestOptions = isInit
? {
timeout: Number(config.initTimeout) || 60000,
}
: undefined;
// Get request options from server configuration, with fallbacks
const serverRequestOptions = conf.options || {};
const requestOptions = {
timeout: serverRequestOptions.timeout || 60000,
resetTimeoutOnProgress: serverRequestOptions.resetTimeoutOnProgress || false,
maxTotalTimeout: serverRequestOptions.maxTotalTimeout,
};
client
.connect(transport, { timeout: timeout })
.connect(transport, initRequestOptions || requestOptions)
.then(() => {
console.log(`Successfully connected client for server: ${name}`);
client
.listTools({}, { timeout: timeout })
.listTools({}, initRequestOptions || requestOptions)
.then((tools) => {
console.log(`Successfully listed ${tools.tools.length} tools for server: ${name}`);
const serverInfo = getServerByName(name);
@@ -276,6 +289,7 @@ export const initializeClientsFromSettings = (isInit: boolean): ServerInfo[] =>
tools: [],
client,
transport,
options: requestOptions,
createTime: Date.now(),
});
console.log(`Initialized client for server: ${name}`);
@@ -696,14 +710,12 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
// Special handling for call_tool
if (request.params.name === 'call_tool') {
let { toolName, arguments: toolArgs = {} } = request.params.arguments || {};
let { toolName } = request.params.arguments || {};
if (!toolName) {
throw new Error('toolName parameter is required');
}
// arguments parameter is now optional
const { arguments: toolArgs = {} } = request.params.arguments || {};
let targetServerInfo: ServerInfo | undefined;
if (extra && extra.server) {
targetServerInfo = getServerByName(extra.server);
@@ -744,10 +756,14 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
toolName = toolName.startsWith(`${targetServerInfo.name}-`)
? toolName.replace(`${targetServerInfo.name}-`, '')
: toolName;
const result = await client.callTool({
name: toolName,
arguments: finalArgs,
});
const result = await client.callTool(
{
name: toolName,
arguments: finalArgs,
},
undefined,
targetServerInfo.options || {},
);
console.log(`Tool invocation result: ${JSON.stringify(result)}`);
return result;
@@ -766,7 +782,7 @@ export const handleCallToolRequest = async (request: any, extra: any) => {
request.params.name = request.params.name.startsWith(`${serverInfo.name}-`)
? request.params.name.replace(`${serverInfo.name}-`, '')
: request.params.name;
const result = await client.callTool(request.params);
const result = await client.callTool(request.params, undefined, serverInfo.options || {});
console.log(`Tool call result: ${JSON.stringify(result)}`);
return result;
} catch (error) {

View File

@@ -2,6 +2,7 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { RequestOptions } from '@modelcontextprotocol/sdk/shared/protocol.js';
import { SmartRoutingConfig } from '../utils/smartRouting.js';
// User interface
@@ -107,6 +108,7 @@ export interface ServerConfig {
enabled?: boolean; // Flag to enable/disable the server
keepAliveInterval?: number; // Keep-alive ping interval in milliseconds (default: 60000ms for SSE servers)
tools?: Record<string, { enabled: boolean; description?: string }>; // Tool-specific configurations with enable/disable state and custom descriptions
options?: Partial<Pick<RequestOptions, 'timeout' | 'resetTimeoutOnProgress' | 'maxTotalTimeout'>>; // MCP request options configuration
}
// Information about a server's status and tools
@@ -117,6 +119,7 @@ export interface ServerInfo {
tools: ToolInfo[]; // List of tools available on the server
client?: Client; // Client instance for communication
transport?: SSEClientTransport | StdioClientTransport | StreamableHTTPClientTransport; // Transport mechanism used
options?: RequestOptions; // Options for requests
createTime: number; // Timestamp of when the server was created
enabled?: boolean; // Flag to indicate if the server is enabled
keepAliveIntervalId?: NodeJS.Timeout; // Timer ID for keep-alive ping interval