diff --git a/src/index.ts b/src/index.ts index ef48938..aafa95c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,7 +8,30 @@ import "dotenv/config"; import logger from "./logger.js"; import { BrowserStackMcpServer } from "./server-factory.js"; +function handleCliMetadataFlags(args = process.argv.slice(2)): boolean { + if (args.includes("--version") || args.includes("-v")) { + console.log(packageJson.version); + return true; + } + + if (args.includes("--help") || args.includes("-h")) { + console.log(`BrowserStack MCP Server + +Usage: + browserstack-mcp-server [--version] [--help] + +Environment: + BROWSERSTACK_USERNAME BrowserStack account username + BROWSERSTACK_ACCESS_KEY BrowserStack account access key`); + return true; + } + + return false; +} + async function main() { + if (handleCliMetadataFlags()) return; + logger.info( "Launching BrowserStack MCP server, version %s", packageJson.version, diff --git a/tests/cli-metadata.test.ts b/tests/cli-metadata.test.ts new file mode 100644 index 0000000..bba9bf5 --- /dev/null +++ b/tests/cli-metadata.test.ts @@ -0,0 +1,52 @@ +import { execFile } from "node:child_process"; +import { readFile } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { promisify } from "node:util"; +import { describe, expect, it } from "vitest"; + +const execFileAsync = promisify(execFile); +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const packageJson = JSON.parse( + await readFile(path.join(root, "package.json"), "utf8"), +); + +async function runCli(args: string[]) { + const env = { ...process.env }; + delete env.BROWSERSTACK_USERNAME; + delete env.BROWSERSTACK_ACCESS_KEY; + delete env.npm_config_npm_globalconfig; + delete env.npm_config_verify_deps_before_run; + delete env.npm_config__jsr_registry; + + try { + const { stdout, stderr } = await execFileAsync( + process.execPath, + ["--import", "tsx", "src/index.ts", ...args], + { cwd: root, env }, + ); + return { code: 0, stdout, stderr }; + } catch (error: any) { + return { + code: error.code, + stdout: error.stdout ?? "", + stderr: error.stderr ?? "", + }; + } +} + +describe("CLI metadata flags", () => { + it("prints the package version without requiring credentials", async () => { + const result = await runCli(["--version"]); + expect(result.code).toBe(0); + expect(result.stdout.trim()).toBe(packageJson.version); + expect(result.stderr).not.toContain("BROWSERSTACK_USERNAME"); + }); + + it("prints help without requiring credentials", async () => { + const result = await runCli(["--help"]); + expect(result.code).toBe(0); + expect(result.stdout).toContain("BrowserStack MCP Server"); + expect(result.stderr).not.toContain("BROWSERSTACK_USERNAME"); + }); +});