Implement default-server support
- Auto-select server when --config is used without --server - Use 'default-server' if it exists in config - Use single server if only one is defined - Show helpful error if multiple servers exist without default - Add tests for all default-server scenarios
This commit is contained in:
parent
a7675d1be2
commit
0e2906c4c4
2 changed files with 132 additions and 12 deletions
|
|
@ -780,6 +780,102 @@ async function runTests() {
|
||||||
"tools/list",
|
"tools/list",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`\n${colors.YELLOW}=== Running Default Server Tests ===${colors.NC}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create config with single server for auto-selection
|
||||||
|
const singleServerConfigPath = path.join(TEMP_DIR, "single-server-config.json");
|
||||||
|
fs.writeFileSync(
|
||||||
|
singleServerConfigPath,
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
mcpServers: {
|
||||||
|
"only-server": {
|
||||||
|
command: "npx",
|
||||||
|
args: ["@modelcontextprotocol/server-everything"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create config with default-server
|
||||||
|
const defaultServerConfigPath = path.join(TEMP_DIR, "default-server-config.json");
|
||||||
|
fs.writeFileSync(
|
||||||
|
defaultServerConfigPath,
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
mcpServers: {
|
||||||
|
"default-server": {
|
||||||
|
command: "npx",
|
||||||
|
args: ["@modelcontextprotocol/server-everything"],
|
||||||
|
},
|
||||||
|
"other-server": {
|
||||||
|
command: "node",
|
||||||
|
args: ["other.js"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Create config with multiple servers (no default)
|
||||||
|
const multiServerConfigPath = path.join(TEMP_DIR, "multi-server-config.json");
|
||||||
|
fs.writeFileSync(
|
||||||
|
multiServerConfigPath,
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
mcpServers: {
|
||||||
|
"server1": {
|
||||||
|
command: "npx",
|
||||||
|
args: ["@modelcontextprotocol/server-everything"],
|
||||||
|
},
|
||||||
|
"server2": {
|
||||||
|
command: "node",
|
||||||
|
args: ["other.js"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test 29: Config with single server auto-selection
|
||||||
|
await runBasicTest(
|
||||||
|
"single_server_auto_select",
|
||||||
|
"--config",
|
||||||
|
singleServerConfigPath,
|
||||||
|
"--cli",
|
||||||
|
"--method",
|
||||||
|
"tools/list",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test 30: Config with default-server auto-selection
|
||||||
|
await runBasicTest(
|
||||||
|
"default_server_auto_select",
|
||||||
|
"--config",
|
||||||
|
defaultServerConfigPath,
|
||||||
|
"--cli",
|
||||||
|
"--method",
|
||||||
|
"tools/list",
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test 31: Config with multiple servers and no default (should fail)
|
||||||
|
await runErrorTest(
|
||||||
|
"multi_server_no_default",
|
||||||
|
"--config",
|
||||||
|
multiServerConfigPath,
|
||||||
|
"--cli",
|
||||||
|
"--method",
|
||||||
|
"tools/list",
|
||||||
|
);
|
||||||
|
|
||||||
console.log(
|
console.log(
|
||||||
`\n${colors.YELLOW}=== Running HTTP Transport Tests ===${colors.NC}`,
|
`\n${colors.YELLOW}=== Running HTTP Transport Tests ===${colors.NC}`,
|
||||||
);
|
);
|
||||||
|
|
@ -799,7 +895,7 @@ async function runTests() {
|
||||||
|
|
||||||
await new Promise((resolve) => setTimeout(resolve, 3000));
|
await new Promise((resolve) => setTimeout(resolve, 3000));
|
||||||
|
|
||||||
// Test 29: HTTP transport inferred from URL ending with /mcp
|
// Test 32: HTTP transport inferred from URL ending with /mcp
|
||||||
await runBasicTest(
|
await runBasicTest(
|
||||||
"http_transport_inferred",
|
"http_transport_inferred",
|
||||||
"http://127.0.0.1:3001/mcp",
|
"http://127.0.0.1:3001/mcp",
|
||||||
|
|
@ -808,7 +904,7 @@ async function runTests() {
|
||||||
"tools/list",
|
"tools/list",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test 30: HTTP transport with explicit --transport http flag
|
// Test 33: HTTP transport with explicit --transport http flag
|
||||||
await runBasicTest(
|
await runBasicTest(
|
||||||
"http_transport_with_explicit_flag",
|
"http_transport_with_explicit_flag",
|
||||||
"http://127.0.0.1:3001/mcp",
|
"http://127.0.0.1:3001/mcp",
|
||||||
|
|
@ -819,7 +915,7 @@ async function runTests() {
|
||||||
"tools/list",
|
"tools/list",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test 31: HTTP transport with suffix and --transport http flag
|
// Test 34: HTTP transport with suffix and --transport http flag
|
||||||
await runBasicTest(
|
await runBasicTest(
|
||||||
"http_transport_with_explicit_flag_and_suffix",
|
"http_transport_with_explicit_flag_and_suffix",
|
||||||
"http://127.0.0.1:3001/mcp",
|
"http://127.0.0.1:3001/mcp",
|
||||||
|
|
@ -830,7 +926,7 @@ async function runTests() {
|
||||||
"tools/list",
|
"tools/list",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test 32: SSE transport given to HTTP server (should fail)
|
// Test 35: SSE transport given to HTTP server (should fail)
|
||||||
await runErrorTest(
|
await runErrorTest(
|
||||||
"sse_transport_given_to_http_server",
|
"sse_transport_given_to_http_server",
|
||||||
"http://127.0.0.1:3001",
|
"http://127.0.0.1:3001",
|
||||||
|
|
@ -841,7 +937,7 @@ async function runTests() {
|
||||||
"tools/list",
|
"tools/list",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test 33: HTTP transport without URL (should fail)
|
// Test 36: HTTP transport without URL (should fail)
|
||||||
await runErrorTest(
|
await runErrorTest(
|
||||||
"http_transport_without_url",
|
"http_transport_without_url",
|
||||||
"--transport",
|
"--transport",
|
||||||
|
|
@ -851,7 +947,7 @@ async function runTests() {
|
||||||
"tools/list",
|
"tools/list",
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test 34: SSE transport without URL (should fail)
|
// Test 37: SSE transport without URL (should fail)
|
||||||
await runErrorTest(
|
await runErrorTest(
|
||||||
"sse_transport_without_url",
|
"sse_transport_without_url",
|
||||||
"--transport",
|
"--transport",
|
||||||
|
|
|
||||||
|
|
@ -220,16 +220,40 @@ function parseArgs(): Args {
|
||||||
// Add back any arguments that came after --
|
// Add back any arguments that came after --
|
||||||
const finalArgs = [...remainingArgs, ...postArgs];
|
const finalArgs = [...remainingArgs, ...postArgs];
|
||||||
|
|
||||||
// Validate that config and server are provided together
|
// Validate config and server options
|
||||||
if (
|
if (!options.config && options.server) {
|
||||||
(options.config && !options.server) ||
|
|
||||||
(!options.config && options.server)
|
|
||||||
) {
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
"Both --config and --server must be provided together. If you specify one, you must specify the other.",
|
"--server requires --config to be specified",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If config is provided without server, try to auto-select
|
||||||
|
if (options.config && !options.server) {
|
||||||
|
const configContent = fs.readFileSync(
|
||||||
|
path.isAbsolute(options.config)
|
||||||
|
? options.config
|
||||||
|
: path.resolve(process.cwd(), options.config),
|
||||||
|
"utf8"
|
||||||
|
);
|
||||||
|
const parsedConfig = JSON.parse(configContent);
|
||||||
|
const servers = Object.keys(parsedConfig.mcpServers || {});
|
||||||
|
|
||||||
|
if (servers.includes("default-server")) {
|
||||||
|
// Use default-server if it exists
|
||||||
|
options.server = "default-server";
|
||||||
|
} else if (servers.length === 1) {
|
||||||
|
// Use the only server if there's just one
|
||||||
|
options.server = servers[0];
|
||||||
|
} else if (servers.length === 0) {
|
||||||
|
throw new Error("No servers found in config file");
|
||||||
|
} else {
|
||||||
|
// Multiple servers, no default-server
|
||||||
|
throw new Error(
|
||||||
|
`Multiple servers found in config file. Please specify one with --server.\nAvailable servers: ${servers.join(", ")}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If config file is specified, load and use the options from the file. We must merge the args
|
// If config file is specified, load and use the options from the file. We must merge the args
|
||||||
// from the command line and the file together, or we will miss the method options (--method,
|
// from the command line and the file together, or we will miss the method options (--method,
|
||||||
// etc.)
|
// etc.)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue