Add CLI and config file support

This commit is contained in:
Nicolas Barraud
2025-03-10 20:19:23 -04:00
parent 0870a81990
commit 4c4c8a0884
20 changed files with 1456 additions and 57 deletions

View File

@@ -1,43 +1,27 @@
#!/usr/bin/env node
import { resolve, dirname } from "path";
import { Command } from "commander";
import fs from "node:fs";
import path from "node:path";
import { dirname, resolve } from "path";
import { spawnPromise } from "spawn-rx";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
function handleError(error) {
let message;
if (error instanceof Error) {
message = error.message;
} else if (typeof error === "string") {
message = error;
} else {
message = "Unknown error";
}
console.error(message);
process.exit(1);
}
function delay(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function main() {
// Parse command line arguments
const args = process.argv.slice(2);
const envVars = {};
const mcpServerArgs = [];
let command = null;
let parsingFlags = true;
for (let i = 0; i < args.length; i++) {
const arg = args[i];
if (parsingFlags && arg === "--") {
parsingFlags = false;
continue;
}
if (parsingFlags && arg === "-e" && i + 1 < args.length) {
const [key, value] = args[++i].split("=");
if (key && value) {
envVars[key] = value;
}
} else if (!command) {
command = arg;
} else {
mcpServerArgs.push(arg);
}
}
async function runWebClient(args) {
const inspectorServerPath = resolve(
__dirname,
"..",
@@ -45,7 +29,6 @@ async function main() {
"build",
"index.js",
);
// Path to the client entry point
const inspectorClientPath = resolve(
__dirname,
@@ -54,63 +37,183 @@ async function main() {
"bin",
"cli.js",
);
const CLIENT_PORT = process.env.CLIENT_PORT ?? "5173";
const SERVER_PORT = process.env.SERVER_PORT ?? "3000";
console.log("Starting MCP inspector...");
const abort = new AbortController();
let cancelled = false;
process.on("SIGINT", () => {
cancelled = true;
abort.abort();
});
const server = spawnPromise(
"node",
[
inspectorServerPath,
...(command ? [`--env`, command] : []),
...(mcpServerArgs ? [`--args=${mcpServerArgs.join(" ")}`] : []),
...(args.command ? [`--env`, args.command] : []),
...(args.args ? [`--args=${args.args.join(" ")}`] : []),
],
{
env: {
...process.env,
PORT: SERVER_PORT,
MCP_ENV_VARS: JSON.stringify(envVars),
MCP_ENV_VARS: JSON.stringify(args.envArgs),
},
signal: abort.signal,
echoOutput: true,
},
);
const client = spawnPromise("node", [inspectorClientPath], {
env: { ...process.env, PORT: CLIENT_PORT },
signal: abort.signal,
echoOutput: true,
});
// Make sure our server/client didn't immediately fail
await Promise.any([server, client, delay(2 * 1000)]);
const portParam = SERVER_PORT === "3000" ? "" : `?proxyPort=${SERVER_PORT}`;
console.log(
`\n🔍 MCP Inspector is up and running at http://localhost:${CLIENT_PORT}${portParam} 🚀`,
);
try {
await Promise.any([server, client]);
} catch (e) {
if (!cancelled || process.env.DEBUG) throw e;
if (!cancelled || process.env.DEBUG) {
throw e;
}
}
return 0;
}
main()
.then((_) => process.exit(0))
.catch((e) => {
console.error(e);
process.exit(1);
async function runCli(args) {
const projectRoot = resolve(__dirname, "..");
const cliPath = resolve(projectRoot, "cli", "build", "index.js");
const abort = new AbortController();
let cancelled = false;
process.on("SIGINT", () => {
cancelled = true;
abort.abort();
});
try {
await spawnPromise("node", [cliPath, args.command, ...args.args], {
env: { ...process.env, ...args.envArgs },
signal: abort.signal,
echoOutput: true,
});
} catch (e) {
if (!cancelled || process.env.DEBUG) {
throw e;
}
}
}
function loadConfigFile(configPath, serverName) {
try {
const resolvedConfigPath = path.isAbsolute(configPath)
? configPath
: path.resolve(process.cwd(), configPath);
if (!fs.existsSync(resolvedConfigPath)) {
throw new Error(`Config file not found: ${resolvedConfigPath}`);
}
const configContent = fs.readFileSync(resolvedConfigPath, "utf8");
const parsedConfig = JSON.parse(configContent);
if (!parsedConfig.mcpServers || !parsedConfig.mcpServers[serverName]) {
const availableServers = Object.keys(parsedConfig.mcpServers || {}).join(
", ",
);
throw new Error(
`Server '${serverName}' not found in config file. Available servers: ${availableServers}`,
);
}
const serverConfig = parsedConfig.mcpServers[serverName];
return serverConfig;
} catch (err) {
if (err instanceof SyntaxError) {
throw new Error(`Invalid JSON in config file: ${err.message}`);
}
throw err;
}
}
function parseKeyValuePair(value, previous = {}) {
const parts = value.split("=");
const key = parts[0];
const val = parts.slice(1).join("=");
if (val === undefined || val === "") {
throw new Error(
`Invalid parameter format: ${value}. Use key=value format.`,
);
}
return { ...previous, [key]: val };
}
function parseArgs() {
const program = new Command();
const argSeparatorIndex = process.argv.indexOf("--");
let preArgs = process.argv;
let postArgs = [];
if (argSeparatorIndex !== -1) {
preArgs = process.argv.slice(0, argSeparatorIndex);
postArgs = process.argv.slice(argSeparatorIndex + 1);
}
program
.name("inspector-bin")
.allowExcessArguments()
.allowUnknownOption()
.option(
"-e <env>",
"environment variables in KEY=VALUE format",
parseKeyValuePair,
{},
)
.option("--config <path>", "config file path")
.option("--server <n>", "server name from config file")
.option("--cli", "enable CLI mode");
// Parse only the arguments before --
program.parse(preArgs);
const options = program.opts();
const remainingArgs = program.args;
// Add back any arguments that came after --
const finalArgs = [...remainingArgs, ...postArgs];
// Validate that config and server are provided together
if (
(options.config && !options.server) ||
(!options.config && options.server)
) {
throw new Error(
"Both --config and --server must be provided together. If you specify one, you must specify the other.",
);
}
// 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,
// etc.)
if (options.config && options.server) {
const config = loadConfigFile(options.config, options.server);
return {
command: config.command,
args: [...(config.args || []), ...finalArgs],
envArgs: { ...(config.env || {}), ...(options.e || {}) },
cli: options.cli || false,
};
}
// Otherwise use command line arguments
const command = finalArgs[0] || "";
const args = finalArgs.slice(1);
return {
command,
args,
envArgs: options.e || {},
cli: options.cli || false,
};
}
async function main() {
process.on("uncaughtException", (error) => {
handleError(error);
});
try {
const args = parseArgs();
console.log(args);
if (args.cli) {
runCli(args);
} else {
await runWebClient(args);
}
} catch (error) {
handleError(error);
}
}
main();

23
bin/package.json Normal file
View File

@@ -0,0 +1,23 @@
{
"name": "@modelcontextprotocol/inspector-bin",
"version": "0.5.1",
"description": "Model Context Protocol inspector",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",
"homepage": "https://modelcontextprotocol.io",
"bugs": "https://github.com/modelcontextprotocol/inspector/issues",
"type": "module",
"bin": {
"mcp-inspector": "./cli.js"
},
"files": [
"cli.js"
],
"scripts": {
"build": "tsc",
"postbuild": "chmod +x build/index.js && cp build/index.js cli.js",
"test": "./tests/cli-tests.sh"
},
"dependencies": {},
"devDependencies": {}
}

289
bin/src/index.ts Normal file
View File

@@ -0,0 +1,289 @@
#!/usr/bin/env node
import { Command } from "commander";
import fs from "node:fs";
import path from "node:path";
import { dirname, resolve } from "path";
import { spawnPromise } from "spawn-rx";
import { fileURLToPath } from "url";
const __dirname = dirname(fileURLToPath(import.meta.url));
type Args = {
command: string;
args: string[];
envArgs: Record<string, string>;
cli: boolean;
};
type CliOptions = {
e?: Record<string, string>;
config?: string;
server?: string;
cli?: boolean;
};
type ServerConfig = {
command: string;
args?: string[];
env?: Record<string, string>;
};
function handleError(error: unknown): never {
let message: string;
if (error instanceof Error) {
message = error.message;
} else if (typeof error === "string") {
message = error;
} else {
message = "Unknown error";
}
console.error(message);
process.exit(1);
}
function delay(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function runWebClient(args: Args): Promise<void> {
const inspectorServerPath = resolve(
__dirname,
"..",
"server",
"build",
"index.js",
);
// Path to the client entry point
const inspectorClientPath = resolve(
__dirname,
"..",
"client",
"bin",
"cli.js",
);
const CLIENT_PORT = process.env.CLIENT_PORT ?? "5173";
const SERVER_PORT = process.env.SERVER_PORT ?? "3000";
console.log("Starting MCP inspector...");
const abort = new AbortController();
let cancelled = false;
process.on("SIGINT", () => {
cancelled = true;
abort.abort();
});
const server = spawnPromise(
"node",
[
inspectorServerPath,
...(args.command ? [`--env`, args.command] : []),
...(args.args ? [`--args=${args.args.join(" ")}`] : []),
],
{
env: {
...process.env,
PORT: SERVER_PORT,
MCP_ENV_VARS: JSON.stringify(args.envArgs),
},
signal: abort.signal,
echoOutput: true,
},
);
const client = spawnPromise("node", [inspectorClientPath], {
env: { ...process.env, PORT: CLIENT_PORT },
signal: abort.signal,
echoOutput: true,
});
// Make sure our server/client didn't immediately fail
await Promise.any([server, client, delay(2 * 1000)]);
const portParam = SERVER_PORT === "3000" ? "" : `?proxyPort=${SERVER_PORT}`;
console.log(
`\n🔍 MCP Inspector is up and running at http://localhost:${CLIENT_PORT}${portParam} 🚀`,
);
try {
await Promise.any([server, client]);
} catch (e) {
if (!cancelled || process.env.DEBUG) {
throw e;
}
}
}
async function runCli(args: Args): Promise<void> {
const projectRoot = resolve(__dirname, "..");
const cliPath = resolve(projectRoot, "cli", "build", "index.js");
const abort = new AbortController();
let cancelled = false;
process.on("SIGINT", () => {
cancelled = true;
abort.abort();
});
try {
await spawnPromise("node", [cliPath, args.command, ...args.args], {
env: { ...process.env, ...args.envArgs },
signal: abort.signal,
echoOutput: true,
});
} catch (e) {
if (!cancelled || process.env.DEBUG) {
throw e;
}
}
}
function loadConfigFile(configPath: string, serverName: string): ServerConfig {
try {
const resolvedConfigPath = path.isAbsolute(configPath)
? configPath
: path.resolve(process.cwd(), configPath);
if (!fs.existsSync(resolvedConfigPath)) {
throw new Error(`Config file not found: ${resolvedConfigPath}`);
}
const configContent = fs.readFileSync(resolvedConfigPath, "utf8");
const parsedConfig = JSON.parse(configContent);
if (!parsedConfig.mcpServers || !parsedConfig.mcpServers[serverName]) {
const availableServers = Object.keys(parsedConfig.mcpServers || {}).join(
", ",
);
throw new Error(
`Server '${serverName}' not found in config file. Available servers: ${availableServers}`,
);
}
const serverConfig = parsedConfig.mcpServers[serverName];
return serverConfig;
} catch (err: unknown) {
if (err instanceof SyntaxError) {
throw new Error(`Invalid JSON in config file: ${err.message}`);
}
throw err;
}
}
function parseKeyValuePair(
value: string,
previous: Record<string, string> = {},
): Record<string, string> {
const parts = value.split("=");
const key = parts[0];
const val = parts.slice(1).join("=");
if (val === undefined || val === "") {
throw new Error(
`Invalid parameter format: ${value}. Use key=value format.`,
);
}
return { ...previous, [key as string]: val };
}
function parseArgs(): Args {
const program = new Command();
const argSeparatorIndex = process.argv.indexOf("--");
let preArgs = process.argv;
let postArgs: string[] = [];
if (argSeparatorIndex !== -1) {
preArgs = process.argv.slice(0, argSeparatorIndex);
postArgs = process.argv.slice(argSeparatorIndex + 1);
}
program
.name("inspector-bin")
.allowExcessArguments()
.allowUnknownOption()
.option(
"-e <env>",
"environment variables in KEY=VALUE format",
parseKeyValuePair,
{},
)
.option("--config <path>", "config file path")
.option("--server <n>", "server name from config file")
.option("--cli", "enable CLI mode");
// Parse only the arguments before --
program.parse(preArgs);
const options = program.opts() as CliOptions;
const remainingArgs = program.args;
// Add back any arguments that came after --
const finalArgs = [...remainingArgs, ...postArgs];
// Validate that config and server are provided together
if (
(options.config && !options.server) ||
(!options.config && options.server)
) {
throw new Error(
"Both --config and --server must be provided together. If you specify one, you must specify the other.",
);
}
// 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,
// etc.)
if (options.config && options.server) {
const config = loadConfigFile(options.config, options.server);
return {
command: config.command,
args: [...(config.args || []), ...finalArgs],
envArgs: { ...(config.env || {}), ...(options.e || {}) },
cli: options.cli || false,
};
}
// Otherwise use command line arguments
const command = finalArgs[0] || "";
const args = finalArgs.slice(1);
return {
command,
args,
envArgs: options.e || {},
cli: options.cli || false,
};
}
async function main(): Promise<void> {
process.on("uncaughtException", (error) => {
handleError(error);
});
try {
const args = parseArgs();
if (args.cli) {
runCli(args);
} else {
await runWebClient(args);
}
} catch (error) {
handleError(error);
}
}
main();

231
bin/tests/cli-tests.sh Executable file
View File

@@ -0,0 +1,231 @@
#!/bin/bash
# Colors for output
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
BLUE='\033[0;34m'
ORANGE='\033[0;33m'
NC='\033[0m' # No Color
# Track test results
PASSED_TESTS=0
FAILED_TESTS=0
SKIPPED_TESTS=0
TOTAL_TESTS=0
echo -e "${YELLOW}=== MCP Inspector CLI Test Script ===${NC}"
echo -e "${BLUE}This script tests the MCP Inspector CLI's ability to handle various command line options:${NC}"
echo -e "${BLUE}- Basic CLI mode${NC}"
echo -e "${BLUE}- Environment variables (-e)${NC}"
echo -e "${BLUE}- Config file (--config)${NC}"
echo -e "${BLUE}- Server selection (--server)${NC}"
echo -e "${BLUE}- Method selection (--method)${NC}"
echo -e "${BLUE}- Tool-related options (--tool-name, --tool-args)${NC}"
echo -e "${BLUE}- Resource-related options (--uri)${NC}"
echo -e "${BLUE}- Prompt-related options (--prompt-name, --prompt-args)${NC}"
echo -e "${BLUE}- Logging options (--log-level)${NC}"
echo ""
# Change to the bin directory
cd "$(dirname "$0")/.."
BIN_DIR="$(pwd)"
PROJECT_ROOT="$(dirname "$BIN_DIR")"
# Compile bin and cli projects
echo -e "${YELLOW}Compiling MCP Inspector bin and cli...${NC}"
cd "$BIN_DIR"
npm run build
cd "$PROJECT_ROOT/cli"
npm run build
cd "$BIN_DIR"
# Create a symbolic link to handle path resolution
echo -e "${YELLOW}Setting up environment for tests...${NC}"
PARENT_DIR="$(dirname "$PROJECT_ROOT")"
# Define the test server command using npx
TEST_CMD="npx"
TEST_ARGS=("@modelcontextprotocol/server-everything")
# Create output directory for test results
OUTPUT_DIR="$BIN_DIR/tests/output"
mkdir -p "$OUTPUT_DIR"
# Create a temporary directory for test files
TEMP_DIR=$(mktemp -d)
trap 'rm -rf "$TEMP_DIR"' EXIT INT TERM
# Use the existing sample config file
echo -e "${BLUE}Using existing sample config file: $PROJECT_ROOT/sample-config.json${NC}"
cat "$PROJECT_ROOT/sample-config.json"
# Create an invalid config file for testing
echo '{
"mcpServers": {
"invalid": {' > "$TEMP_DIR/invalid-config.json"
# Function to run a basic test
run_basic_test() {
local test_name=$1
local output_file="$OUTPUT_DIR/${test_name//\//_}.log"
shift
echo -e "\n${YELLOW}Testing: ${test_name}${NC}"
TOTAL_TESTS=$((TOTAL_TESTS + 1))
# Run the command and capture output
echo -e "${BLUE}Command: node ${BIN_DIR}/cli.js $*${NC}"
node "$BIN_DIR/cli.js" "$@" > "$output_file" 2>&1
local exit_code=$?
# Check if the test passed or failed
if [ $exit_code -eq 0 ]; then
echo -e "${GREEN}✓ Test passed: ${test_name}${NC}"
echo -e "${BLUE}First few lines of output:${NC}"
head -n 5 "$output_file" | sed 's/^/ /'
PASSED_TESTS=$((PASSED_TESTS + 1))
else
echo -e "${RED}✗ Test failed: ${test_name}${NC}"
echo -e "${RED}Error output:${NC}"
cat "$output_file" | sed 's/^/ /'
FAILED_TESTS=$((FAILED_TESTS + 1))
# Stop after any error is encountered
echo -e "${YELLOW}Stopping tests due to error. Please validate and fix before continuing.${NC}"
exit 1
fi
}
# Function to run an error test (expected to fail)
run_error_test() {
local test_name=$1
local output_file="$OUTPUT_DIR/${test_name//\//_}.log"
shift
echo -e "\n${YELLOW}Testing error case: ${test_name}${NC}"
TOTAL_TESTS=$((TOTAL_TESTS + 1))
# Run the command and capture output
echo -e "${BLUE}Command: node ${BIN_DIR}/cli.js $*${NC}"
node "$BIN_DIR/cli.js" "$@" > "$output_file" 2>&1
local exit_code=$?
# For error tests, we expect a non-zero exit code
if [ $exit_code -ne 0 ]; then
echo -e "${GREEN}✓ Error test passed: ${test_name}${NC}"
echo -e "${BLUE}Error output (expected):${NC}"
head -n 5 "$output_file" | sed 's/^/ /'
PASSED_TESTS=$((PASSED_TESTS + 1))
else
echo -e "${RED}✗ Error test failed: ${test_name} (expected error but got success)${NC}"
echo -e "${RED}Output:${NC}"
cat "$output_file" | sed 's/^/ /'
FAILED_TESTS=$((FAILED_TESTS + 1))
# Stop after any error is encountered
echo -e "${YELLOW}Stopping tests due to error. Please validate and fix before continuing.${NC}"
exit 1
fi
}
echo -e "\n${YELLOW}=== Running Basic CLI Mode Tests ===${NC}"
# Test 1: Basic CLI mode with method
run_basic_test "basic_cli_mode" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "tools/list"
# Test 2: CLI mode with non-existent method (should fail)
run_error_test "nonexistent_method" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "nonexistent/method"
# Test 3: CLI mode without method (should fail)
run_error_test "missing_method" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli"
echo -e "\n${YELLOW}=== Running Environment Variable Tests ===${NC}"
# Test 4: CLI mode with environment variables
run_basic_test "env_variables" "${TEST_CMD}" "${TEST_ARGS[@]}" "-e" "KEY1=value1" "-e" "KEY2=value2" "--cli" "--method" "tools/list"
# Test 5: CLI mode with invalid environment variable format (should fail)
run_error_test "invalid_env_format" "${TEST_CMD}" "${TEST_ARGS[@]}" "-e" "INVALID_FORMAT" "--cli" "--method" "tools/list"
echo -e "\n${YELLOW}=== Running Config File Tests ===${NC}"
# Test 6: Using config file with CLI mode
run_basic_test "config_file" "--config" "$PROJECT_ROOT/sample-config.json" "--server" "everything" "--cli" "--method" "tools/list"
# Test 7: Using config file without server name (should fail)
run_error_test "config_without_server" "--config" "$PROJECT_ROOT/sample-config.json" "--cli" "--method" "tools/list"
# Test 8: Using server name without config file (should fail)
run_error_test "server_without_config" "--server" "everything" "--cli" "--method" "tools/list"
# Test 9: Using non-existent config file (should fail)
run_error_test "nonexistent_config" "--config" "./nonexistent-config.json" "--server" "everything" "--cli" "--method" "tools/list"
# Test 10: Using invalid config file format (should fail)
run_error_test "invalid_config" "--config" "$TEMP_DIR/invalid-config.json" "--server" "everything" "--cli" "--method" "tools/list"
# Test 11: Using config file with non-existent server (should fail)
run_error_test "nonexistent_server" "--config" "$PROJECT_ROOT/sample-config.json" "--server" "nonexistent" "--cli" "--method" "tools/list"
echo -e "\n${YELLOW}=== Running Tool-Related Tests ===${NC}"
# Test 12: CLI mode with tool call
run_basic_test "tool_call" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "tools/call" "--tool-name" "echo" "--tool-args" "message=Hello"
# Test 13: CLI mode with tool call but missing tool name (should fail)
run_error_test "missing_tool_name" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "tools/call" "--tool-args" "message=Hello"
# Test 14: CLI mode with tool call but invalid tool args format (should fail)
run_error_test "invalid_tool_args" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "tools/call" "--tool-name" "echo" "--tool-args" "invalid_format"
# Test 15: CLI mode with multiple tool args
run_basic_test "multiple_tool_args" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "tools/call" "--tool-name" "add" "--tool-args" "a=1" "b=2"
echo -e "\n${YELLOW}=== Running Resource-Related Tests ===${NC}"
# Test 16: CLI mode with resource read
run_basic_test "resource_read" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "resources/read" "--uri" "test://static/resource/1"
# Test 17: CLI mode with resource read but missing URI (should fail)
run_error_test "missing_uri" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "resources/read"
echo -e "\n${YELLOW}=== Running Prompt-Related Tests ===${NC}"
# Test 18: CLI mode with prompt get
run_basic_test "prompt_get" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "prompts/get" "--prompt-name" "simple_prompt"
# Test 19: CLI mode with prompt get and args
run_basic_test "prompt_get_with_args" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "prompts/get" "--prompt-name" "complex_prompt" "--prompt-args" "temperature=0.7" "style=concise"
# Test 20: CLI mode with prompt get but missing prompt name (should fail)
run_error_test "missing_prompt_name" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "prompts/get"
echo -e "\n${YELLOW}=== Running Logging Tests ===${NC}"
# Test 21: CLI mode with log level
run_basic_test "log_level" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "logging/setLevel" "--log-level" "debug"
# Test 22: CLI mode with invalid log level (should fail)
run_error_test "invalid_log_level" "${TEST_CMD}" "${TEST_ARGS[@]}" "--cli" "--method" "logging/setLevel" "--log-level" "invalid"
echo -e "\n${YELLOW}=== Running Combined Option Tests ===${NC}"
# Note about the combined options issue
echo -e "${BLUE}Testing combined options with environment variables and config file.${NC}"
# Test 23: CLI mode with config file, environment variables, and tool call
run_basic_test "combined_options" "--config" "$PROJECT_ROOT/sample-config.json" "--server" "everything" "-e" "CLI_ENV_VAR=cli_value" "--cli" "--method" "tools/list"
# Test 24: CLI mode with all possible options (that make sense together)
run_basic_test "all_options" "--config" "$PROJECT_ROOT/sample-config.json" "--server" "everything" "-e" "CLI_ENV_VAR=cli_value" "--cli" "--method" "tools/call" "--tool-name" "echo" "--tool-args" "message=Hello" "--log-level" "debug"
# Print test summary
echo -e "\n${YELLOW}=== Test Summary ===${NC}"
echo -e "${GREEN}Passed: $PASSED_TESTS${NC}"
echo -e "${RED}Failed: $FAILED_TESTS${NC}"
echo -e "${ORANGE}Skipped: $SKIPPED_TESTS${NC}"
echo -e "Total: $TOTAL_TESTS"
echo -e "${BLUE}Detailed logs saved to: $OUTPUT_DIR${NC}"
echo -e "\n${GREEN}All tests completed!${NC}"

16
bin/tsconfig.json Normal file
View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "packages", "**/*.spec.ts"]
}