fastmcp 4.22.7 → 4.22.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/FastMCP.cjs CHANGED
@@ -11,7 +11,7 @@
11
11
 
12
12
 
13
13
 
14
- var _chunkQICOIGCHcjs = require('./chunk-QICOIGCH.cjs');
14
+ var _chunkYDWOFVQNcjs = require('./chunk-YDWOFVQN.cjs');
15
15
 
16
16
 
17
17
 
@@ -50,5 +50,5 @@ require('./chunk-O22SYZMC.cjs');
50
50
 
51
51
 
52
52
 
53
- exports.AuthProvider = _chunkYLLBANV4cjs.AuthProvider; exports.AzureProvider = _chunkYLLBANV4cjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkQICOIGCHcjs.DiscoveryDocumentCache; exports.FastMCP = _chunkQICOIGCHcjs.FastMCP; exports.FastMCPError = _chunkQICOIGCHcjs.FastMCPError; exports.FastMCPSession = _chunkQICOIGCHcjs.FastMCPSession; exports.GitHubProvider = _chunkYLLBANV4cjs.GitHubProvider; exports.GoogleProvider = _chunkYLLBANV4cjs.GoogleProvider; exports.MEDIA_FETCH_TIMEOUT_MS = _chunkQICOIGCHcjs.MEDIA_FETCH_TIMEOUT_MS; exports.OAuthProvider = _chunkYLLBANV4cjs.OAuthProvider; exports.ServerState = _chunkQICOIGCHcjs.ServerState; exports.SessionError = _chunkQICOIGCHcjs.SessionError; exports.UnexpectedStateError = _chunkQICOIGCHcjs.UnexpectedStateError; exports.UserError = _chunkQICOIGCHcjs.UserError; exports.audioContent = _chunkQICOIGCHcjs.audioContent; exports.getAuthSession = _chunkYLLBANV4cjs.getAuthSession; exports.imageContent = _chunkQICOIGCHcjs.imageContent; exports.jsonSchemaAdapter = _chunkQICOIGCHcjs.jsonSchemaAdapter; exports.requireAll = _chunkYLLBANV4cjs.requireAll; exports.requireAny = _chunkYLLBANV4cjs.requireAny; exports.requireAuth = _chunkYLLBANV4cjs.requireAuth; exports.requireRole = _chunkYLLBANV4cjs.requireRole; exports.requireScopes = _chunkYLLBANV4cjs.requireScopes;
53
+ exports.AuthProvider = _chunkYLLBANV4cjs.AuthProvider; exports.AzureProvider = _chunkYLLBANV4cjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkYDWOFVQNcjs.DiscoveryDocumentCache; exports.FastMCP = _chunkYDWOFVQNcjs.FastMCP; exports.FastMCPError = _chunkYDWOFVQNcjs.FastMCPError; exports.FastMCPSession = _chunkYDWOFVQNcjs.FastMCPSession; exports.GitHubProvider = _chunkYLLBANV4cjs.GitHubProvider; exports.GoogleProvider = _chunkYLLBANV4cjs.GoogleProvider; exports.MEDIA_FETCH_TIMEOUT_MS = _chunkYDWOFVQNcjs.MEDIA_FETCH_TIMEOUT_MS; exports.OAuthProvider = _chunkYLLBANV4cjs.OAuthProvider; exports.ServerState = _chunkYDWOFVQNcjs.ServerState; exports.SessionError = _chunkYDWOFVQNcjs.SessionError; exports.UnexpectedStateError = _chunkYDWOFVQNcjs.UnexpectedStateError; exports.UserError = _chunkYDWOFVQNcjs.UserError; exports.audioContent = _chunkYDWOFVQNcjs.audioContent; exports.getAuthSession = _chunkYLLBANV4cjs.getAuthSession; exports.imageContent = _chunkYDWOFVQNcjs.imageContent; exports.jsonSchemaAdapter = _chunkYDWOFVQNcjs.jsonSchemaAdapter; exports.requireAll = _chunkYLLBANV4cjs.requireAll; exports.requireAny = _chunkYLLBANV4cjs.requireAny; exports.requireAuth = _chunkYLLBANV4cjs.requireAuth; exports.requireRole = _chunkYLLBANV4cjs.requireRole; exports.requireScopes = _chunkYLLBANV4cjs.requireScopes;
54
54
  //# sourceMappingURL=FastMCP.cjs.map
package/dist/FastMCP.js CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  audioContent,
12
12
  imageContent,
13
13
  jsonSchemaAdapter
14
- } from "./chunk-NI4JFIL4.js";
14
+ } from "./chunk-PVW7IVUE.js";
15
15
  import {
16
16
  AuthProvider,
17
17
  AzureProvider,
@@ -318,5 +318,5 @@ await _yargs2.default.call(void 0, _helpers.hideBin.call(void 0, process.argv)).
318
318
  process.exit(1);
319
319
  }
320
320
  }
321
- ).help().parseAsync();
321
+ ).demandCommand(1).strict().help().parseAsync();
322
322
  //# sourceMappingURL=fastmcp.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/bin/fastmcp.cjs","../../src/bin/fastmcp.ts","../../src/bin/devCommand.ts","../../src/bin/validateCommand.ts"],"names":["yargs"],"mappings":"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","file":"/home/runner/work/fastmcp/fastmcp/dist/bin/fastmcp.cjs","sourcesContent":[null,"#!/usr/bin/env node\n\nimport { execa } from \"execa\";\nimport { mkdtemp, rm, writeFile } from \"fs/promises\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nimport { buildDevCommand, buildDevConfig } from \"./devCommand.js\";\nimport {\n buildStructureCheckCommand,\n buildTypeCheckCommand,\n formatCommandFailure,\n withTypeCheckProject,\n} from \"./validateCommand.js\";\n\nawait yargs(hideBin(process.argv))\n .scriptName(\"fastmcp\")\n .command(\n \"dev <file>\",\n \"Start a development server\",\n (yargs) => {\n return yargs\n .positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n })\n\n .option(\"args\", {\n describe:\n \"JSON arguments passed to the tool (requires --tool), e.g. '{\\\"a\\\":1}'\",\n type: \"string\",\n })\n\n .option(\"tool\", {\n alias: \"t\",\n describe:\n \"Call a tool non-interactively instead of launching the inspector\",\n type: \"string\",\n })\n\n .option(\"watch\", {\n alias: \"w\",\n default: false,\n describe: \"Watch for file changes and restart server\",\n type: \"boolean\",\n })\n\n .option(\"verbose\", {\n alias: \"v\",\n default: false,\n describe: \"Enable verbose logging\",\n type: \"boolean\",\n });\n },\n\n async (argv) => {\n let configDir: string | undefined;\n\n try {\n if (argv.args !== undefined && !argv.tool) {\n console.error(\"[FastMCP Error] --args requires --tool\");\n process.exitCode = 1;\n return;\n }\n\n if (argv.tool && argv.watch) {\n console.warn(\n \"[FastMCP] --watch is ignored when calling a tool with --tool: the server runs for a single call.\",\n );\n }\n\n let configPath: string | undefined;\n\n if (argv.tool) {\n configDir = await mkdtemp(join(tmpdir(), \"fastmcp-dev-\"));\n configPath = join(configDir, \"mcp-cli.json\");\n await writeFile(configPath, buildDevConfig(argv.file), \"utf8\");\n }\n\n const [command, ...commandArgs] = buildDevCommand({\n configPath,\n file: argv.file,\n tool: argv.tool,\n toolArgs: argv.args,\n watch: argv.watch,\n });\n\n if (argv.verbose) {\n console.log(\n `[FastMCP] Starting server: ${[command, ...commandArgs].join(\" \")}`,\n );\n console.log(`[FastMCP] File: ${argv.file}`);\n console.log(\n `[FastMCP] Watch mode: ${argv.watch ? \"enabled\" : \"disabled\"}`,\n );\n\n if (argv.tool) {\n console.log(`[FastMCP] Tool: ${argv.tool}`);\n }\n }\n\n await execa(command, commandArgs, {\n stderr: \"inherit\",\n stdin: \"inherit\",\n stdout: \"inherit\",\n });\n } catch (error) {\n console.error(\n \"[FastMCP Error] Failed to start development server:\",\n error instanceof Error ? error.message : String(error),\n );\n\n if (argv.verbose && error instanceof Error && error.stack) {\n console.error(\"[FastMCP Debug] Stack trace:\", error.stack);\n }\n\n // Not process.exit(): that would skip the `finally` block below and\n // leak the temporary config directory on every failed tool call.\n process.exitCode = 1;\n } finally {\n if (configDir) {\n await rm(configDir, { force: true, recursive: true });\n }\n }\n },\n )\n\n .command(\n \"inspect <file>\",\n \"Inspect a server file\",\n (yargs) => {\n return yargs.positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n });\n },\n\n async (argv) => {\n try {\n await execa({\n stderr: \"inherit\",\n stdout: \"inherit\",\n })`npx @modelcontextprotocol/inspector npx tsx ${argv.file}`;\n } catch (error) {\n console.error(\n \"[FastMCP Error] Failed to inspect server:\",\n error instanceof Error ? error.message : String(error),\n );\n\n process.exit(1);\n }\n },\n )\n\n .command(\n \"validate <file>\",\n \"Validate a FastMCP server file for syntax and basic structure\",\n (yargs) => {\n return yargs\n .positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n })\n\n .option(\"strict\", {\n alias: \"s\",\n default: false,\n describe: \"Enable strict validation (type checking)\",\n type: \"boolean\",\n });\n },\n\n async (argv) => {\n try {\n const { existsSync } = await import(\"fs\");\n const { resolve } = await import(\"path\");\n const filePath = resolve(argv.file);\n\n if (!existsSync(filePath)) {\n console.error(`[FastMCP Error] File not found: ${filePath}`);\n process.exit(1);\n }\n\n console.log(`[FastMCP] Validating server file: ${filePath}`);\n\n try {\n await withTypeCheckProject(filePath, (project) => {\n const [typeCheckCommand, ...typeCheckArgs] = buildTypeCheckCommand(\n filePath,\n { project, strict: argv.strict },\n );\n\n return execa(typeCheckCommand, typeCheckArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\n });\n });\n\n console.log(\"[FastMCP] ✓ TypeScript compilation successful\");\n } catch (tsError) {\n console.error(\"[FastMCP] ✗ TypeScript compilation failed\");\n\n const diagnostics = formatCommandFailure(tsError);\n\n if (diagnostics) {\n console.error(diagnostics);\n }\n\n process.exit(1);\n }\n\n const [structureCommand, ...structureArgs] =\n buildStructureCheckCommand(filePath);\n\n try {\n await execa(structureCommand, structureArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\n });\n } catch (structureError) {\n // The child reports the reason on stderr, which execa captures. Without\n // replaying it the user only ever sees the generic hint below, even when\n // the server file has an error they could act on.\n const reason = formatCommandFailure(structureError);\n\n if (reason) {\n console.error(reason);\n } else {\n console.error(\"[FastMCP] ✗ Server structure validation failed\");\n console.error(\n \"Make sure the file properly imports and uses FastMCP\",\n );\n }\n\n process.exit(1);\n }\n\n console.log(\n \"[FastMCP] ✓ All validations passed! Server file looks good.\",\n );\n } catch (error) {\n console.error(\n \"[FastMCP Error] Validation failed:\",\n error instanceof Error ? error.message : String(error),\n );\n\n process.exit(1);\n }\n },\n )\n\n .help()\n .parseAsync();\n","export type DevCommandOptions = {\n /**\n * Path to a temporary mcp-cli config file that registers the dev server.\n * Only used in non-interactive mode (when `tool` is set).\n */\n configPath?: string;\n /**\n * Path to the server file to run.\n */\n file: string;\n /**\n * Name of the tool to call non-interactively. When omitted, the dev\n * command launches the interactive mcp-cli inspector instead.\n */\n tool?: string;\n /**\n * JSON string of arguments forwarded to the tool via mcp-cli `--args`.\n * Only used in non-interactive mode.\n */\n toolArgs?: string;\n /**\n * Watch the file for changes and restart the server. Only used in\n * interactive mode; a non-interactive call runs the server once.\n */\n watch?: boolean;\n};\n\n/**\n * The server name registered in the generated mcp-cli config. mcp-cli\n * addresses non-interactive targets as `<server-name>:<tool>`.\n */\nexport const DEV_SERVER_NAME = \"dev\";\n\n/**\n * Build the JSON config that registers the dev server with mcp-cli so it can\n * be invoked non-interactively. mcp-cli's non-interactive mode resolves the\n * server by name from a config file's `mcpServers` map, so an inline command\n * cannot be passed directly alongside `call-tool`.\n *\n * The server is never started in watch mode here: a non-interactive call\n * connects, calls one tool, and exits, so there is nothing to restart into.\n */\nexport const buildDevConfig = (file: string): string =>\n JSON.stringify(\n {\n mcpServers: {\n [DEV_SERVER_NAME]: {\n args: [\"tsx\", file],\n command: \"npx\",\n },\n },\n },\n null,\n 2,\n );\n\n/**\n * Build the argv that the dev command runs.\n *\n * This is an argv array rather than a shell string so that nothing has to be\n * quoted: file paths, tool names and JSON `--args` are passed to the child\n * process verbatim. Quoting through a shell would be wrong on Windows, where\n * cmd.exe treats single quotes as literal characters rather than as quoting.\n *\n * - Without `tool`: launches the interactive @wong2/mcp-cli inspector\n * against an inline `npx tsx <file>` server (existing behaviour).\n * - With `tool`: runs @wong2/mcp-cli in non-interactive mode against a\n * generated config file, calling the named tool and forwarding `--args`.\n */\nexport const buildDevCommand = (\n options: DevCommandOptions,\n): [string, ...string[]] => {\n const { configPath, file, tool, toolArgs, watch = false } = options;\n\n if (tool) {\n if (!configPath) {\n throw new Error(\n \"configPath is required when calling a tool non-interactively\",\n );\n }\n\n return [\n \"npx\",\n \"@wong2/mcp-cli\",\n \"-c\",\n configPath,\n \"call-tool\",\n `${DEV_SERVER_NAME}:${tool}`,\n ...(toolArgs === undefined ? [] : [\"--args\", toolArgs]),\n ];\n }\n\n return [\n \"npx\",\n \"@wong2/mcp-cli\",\n \"npx\",\n \"tsx\",\n ...(watch ? [\"--watch\"] : []),\n file,\n ];\n};\n","import { existsSync } from \"node:fs\";\nimport { rm, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\n/**\n * Compiler options for type-checking a server file with no `tsconfig.json`\n * above it. tsc's own defaults (ES5, CommonJS-era module resolution) cannot\n * even read FastMCP's declarations, which use private class fields and a\n * default import of `http`, so no real server file could pass under them.\n * These describe how a server actually runs instead: as an ES module on a\n * current Node, which can import `.ts` files directly.\n */\nexport const DEFAULT_TYPE_CHECK_OPTIONS = [\n \"--allowImportingTsExtensions\",\n \"--module\",\n \"esnext\",\n \"--moduleResolution\",\n \"bundler\",\n \"--skipLibCheck\",\n \"--target\",\n \"es2022\",\n];\n\n/**\n * The script that `fastmcp validate` runs to check a server file can be\n * imported.\n *\n * The target file is read from `process.argv[1]` instead of being spliced into\n * this source. Splicing is not equivalent: the path would land inside a\n * JavaScript string literal, so the child's own parser would consume the\n * backslashes of a Windows path as string escapes. `C:\\Users\\dev\\server.ts`\n * reaches the import as `C:Usersdevserver.ts`, which throws `ERR_INVALID_URL`\n * and is reported to the user as \"does not import FastMCP\" even though the file\n * is fine.\n *\n * The script exits explicitly once the import settles. Importing a server file\n * normally starts the server, and a running server — a stdio transport waiting\n * on stdin, an HTTP listener — keeps the process alive indefinitely, so\n * validating a server that calls `start()` would otherwise never finish.\n */\nexport const STRUCTURE_CHECK_SCRIPT = `\n(async () => {\n try {\n const { FastMCP } = await import(\"fastmcp\");\n await import(process.argv[1]);\n console.log(\"[FastMCP] ✓ Server structure validation passed\");\n } catch (error) {\n console.error(\"[FastMCP] ✗ Server structure validation failed:\", error.message);\n process.exitCode = 1;\n }\n\n process.exit();\n})();\n`;\n\n/**\n * Build the argv for the type-check step.\n *\n * This is an argv array rather than a shell string so that nothing has to be\n * quoted: the file path is passed to tsc verbatim, so a path containing spaces\n * stays one argument. Quoting through a shell would be wrong on Windows, where\n * cmd.exe re-parses the command line and splits such a path into several root\n * files.\n *\n * Given a `project` (see `withTypeCheckProject`), tsc checks the file through\n * it; without one, the file is passed directly with\n * `DEFAULT_TYPE_CHECK_OPTIONS`.\n */\nexport const buildTypeCheckCommand = (\n file: string,\n { project, strict = false }: { project?: string; strict?: boolean } = {},\n): [string, ...string[]] => [\n \"npx\",\n \"tsc\",\n \"--noEmit\",\n ...(strict ? [\"--strict\"] : []),\n ...(project ? [\"--project\", project] : [...DEFAULT_TYPE_CHECK_OPTIONS, file]),\n];\n\n/**\n * Build a tsconfig that checks only `file`, with the compiler options of the\n * project's own `tsconfig`.\n *\n * `tsc <file>` ignores tsconfig.json altogether and falls back to tsc's\n * defaults, while `tsc --project tsconfig.json` checks every file in the\n * project rather than the one being validated. Extending the project's config\n * and listing just `file` gets both right. A project that is `incremental` or\n * `composite` still writes a `.tsbuildinfo` under `--noEmit`, so both are\n * switched off: validating a file should leave the project untouched.\n */\nexport const buildTypeCheckProject = (tsconfig: string, file: string): string =>\n JSON.stringify({\n compilerOptions: { composite: false, incremental: false },\n extends: `./${basename(tsconfig)}`,\n files: [file],\n include: [],\n });\n\n/**\n * Find the `tsconfig.json` that applies to files in `dir`: the nearest one in\n * it or any of its parents, which is where tsc and editors look too.\n */\nexport const findTsconfig = (dir: string): string | undefined => {\n const candidate = join(dir, \"tsconfig.json\");\n\n if (existsSync(candidate)) {\n return candidate;\n }\n\n const parent = dirname(dir);\n\n return parent === dir ? undefined : findTsconfig(parent);\n};\n\n/**\n * Run `check` with a throwaway tsconfig for `file` (see\n * `buildTypeCheckProject`), or with no project when the file has no\n * `tsconfig.json` above it.\n *\n * The throwaway config is written next to the one it extends and removed once\n * `check` settles. It cannot live in a temporary directory: tsc looks for the\n * `@types` packages it includes by default relative to the config file, so\n * from anywhere else a server using, say, `process.env` would stop compiling.\n */\nexport const withTypeCheckProject = async <T>(\n file: string,\n check: (project?: string) => Promise<T>,\n): Promise<T> => {\n const tsconfig = findTsconfig(dirname(file));\n\n if (!tsconfig) {\n return check();\n }\n\n const project = join(\n dirname(tsconfig),\n `tsconfig.fastmcp-validate-${process.pid}.json`,\n );\n\n await writeFile(project, buildTypeCheckProject(tsconfig, file), \"utf8\");\n\n try {\n return await check(project);\n } finally {\n await rm(project, { force: true });\n }\n};\n\n/**\n * Build the argv for the structure-check step.\n *\n * As above, the file is passed as an argument rather than quoted into a shell\n * command. It is converted to a file URL by the parent process, so the child\n * receives the URL as-is and never has to reconstruct it. The child is the same\n * Node binary running the CLI, so no PATH lookup is involved.\n */\nexport const buildStructureCheckCommand = (\n file: string,\n execPath: string = process.execPath,\n): [string, ...string[]] => [\n execPath,\n \"-e\",\n STRUCTURE_CHECK_SCRIPT,\n pathToFileURL(file).href,\n];\n\n/**\n * The output streams a failed command carries. execa sets both on the error it\n * throws, but they are optional here so the extraction stays honest about not\n * every `Error` having them.\n */\ntype CommandOutputStreams = {\n stderr?: unknown;\n stdout?: unknown;\n};\n\nconst hasOutputStreams = (\n error: Error,\n): error is CommandOutputStreams & Error =>\n \"stdout\" in error || \"stderr\" in error;\n\n/**\n * Extract the output of a failed command.\n *\n * tsc writes its diagnostics to stdout, while a failure to launch the compiler\n * at all (a missing `npx`, for instance) reports on stderr — reading only\n * stderr left the message empty for every real type error. The structure check\n * reports the reason on stderr, which execa captures, so it has to be replayed\n * here as well or the caller can only print a generic hint.\n *\n * An error that did not come from a command at all — the throwaway tsconfig\n * could not be written, say — is reported by its message.\n */\nexport const formatCommandFailure = (error: unknown): string => {\n if (!(error instanceof Error)) {\n return \"\";\n }\n\n if (!hasOutputStreams(error)) {\n return error.message;\n }\n\n const collect = (value: unknown): string =>\n typeof value === \"string\" ? value.trim() : \"\";\n\n return [collect(error.stderr), collect(error.stdout)]\n .filter(Boolean)\n .join(\"\\n\");\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/bin/fastmcp.cjs","../../src/bin/fastmcp.ts","../../src/bin/devCommand.ts","../../src/bin/validateCommand.ts"],"names":["yargs"],"mappings":"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","file":"/home/runner/work/fastmcp/fastmcp/dist/bin/fastmcp.cjs","sourcesContent":[null,"#!/usr/bin/env node\n\nimport { execa } from \"execa\";\nimport { mkdtemp, rm, writeFile } from \"fs/promises\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nimport { buildDevCommand, buildDevConfig } from \"./devCommand.js\";\nimport {\n buildStructureCheckCommand,\n buildTypeCheckCommand,\n formatCommandFailure,\n withTypeCheckProject,\n} from \"./validateCommand.js\";\n\nawait yargs(hideBin(process.argv))\n .scriptName(\"fastmcp\")\n .command(\n \"dev <file>\",\n \"Start a development server\",\n (yargs) => {\n return yargs\n .positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n })\n\n .option(\"args\", {\n describe:\n \"JSON arguments passed to the tool (requires --tool), e.g. '{\\\"a\\\":1}'\",\n type: \"string\",\n })\n\n .option(\"tool\", {\n alias: \"t\",\n describe:\n \"Call a tool non-interactively instead of launching the inspector\",\n type: \"string\",\n })\n\n .option(\"watch\", {\n alias: \"w\",\n default: false,\n describe: \"Watch for file changes and restart server\",\n type: \"boolean\",\n })\n\n .option(\"verbose\", {\n alias: \"v\",\n default: false,\n describe: \"Enable verbose logging\",\n type: \"boolean\",\n });\n },\n\n async (argv) => {\n let configDir: string | undefined;\n\n try {\n if (argv.args !== undefined && !argv.tool) {\n console.error(\"[FastMCP Error] --args requires --tool\");\n process.exitCode = 1;\n return;\n }\n\n if (argv.tool && argv.watch) {\n console.warn(\n \"[FastMCP] --watch is ignored when calling a tool with --tool: the server runs for a single call.\",\n );\n }\n\n let configPath: string | undefined;\n\n if (argv.tool) {\n configDir = await mkdtemp(join(tmpdir(), \"fastmcp-dev-\"));\n configPath = join(configDir, \"mcp-cli.json\");\n await writeFile(configPath, buildDevConfig(argv.file), \"utf8\");\n }\n\n const [command, ...commandArgs] = buildDevCommand({\n configPath,\n file: argv.file,\n tool: argv.tool,\n toolArgs: argv.args,\n watch: argv.watch,\n });\n\n if (argv.verbose) {\n console.log(\n `[FastMCP] Starting server: ${[command, ...commandArgs].join(\" \")}`,\n );\n console.log(`[FastMCP] File: ${argv.file}`);\n console.log(\n `[FastMCP] Watch mode: ${argv.watch ? \"enabled\" : \"disabled\"}`,\n );\n\n if (argv.tool) {\n console.log(`[FastMCP] Tool: ${argv.tool}`);\n }\n }\n\n await execa(command, commandArgs, {\n stderr: \"inherit\",\n stdin: \"inherit\",\n stdout: \"inherit\",\n });\n } catch (error) {\n console.error(\n \"[FastMCP Error] Failed to start development server:\",\n error instanceof Error ? error.message : String(error),\n );\n\n if (argv.verbose && error instanceof Error && error.stack) {\n console.error(\"[FastMCP Debug] Stack trace:\", error.stack);\n }\n\n // Not process.exit(): that would skip the `finally` block below and\n // leak the temporary config directory on every failed tool call.\n process.exitCode = 1;\n } finally {\n if (configDir) {\n await rm(configDir, { force: true, recursive: true });\n }\n }\n },\n )\n\n .command(\n \"inspect <file>\",\n \"Inspect a server file\",\n (yargs) => {\n return yargs.positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n });\n },\n\n async (argv) => {\n try {\n await execa({\n stderr: \"inherit\",\n stdout: \"inherit\",\n })`npx @modelcontextprotocol/inspector npx tsx ${argv.file}`;\n } catch (error) {\n console.error(\n \"[FastMCP Error] Failed to inspect server:\",\n error instanceof Error ? error.message : String(error),\n );\n\n process.exit(1);\n }\n },\n )\n\n .command(\n \"validate <file>\",\n \"Validate a FastMCP server file for syntax and basic structure\",\n (yargs) => {\n return yargs\n .positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n })\n\n .option(\"strict\", {\n alias: \"s\",\n default: false,\n describe: \"Enable strict validation (type checking)\",\n type: \"boolean\",\n });\n },\n\n async (argv) => {\n try {\n const { existsSync } = await import(\"fs\");\n const { resolve } = await import(\"path\");\n const filePath = resolve(argv.file);\n\n if (!existsSync(filePath)) {\n console.error(`[FastMCP Error] File not found: ${filePath}`);\n process.exit(1);\n }\n\n console.log(`[FastMCP] Validating server file: ${filePath}`);\n\n try {\n await withTypeCheckProject(filePath, (project) => {\n const [typeCheckCommand, ...typeCheckArgs] = buildTypeCheckCommand(\n filePath,\n { project, strict: argv.strict },\n );\n\n return execa(typeCheckCommand, typeCheckArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\n });\n });\n\n console.log(\"[FastMCP] ✓ TypeScript compilation successful\");\n } catch (tsError) {\n console.error(\"[FastMCP] ✗ TypeScript compilation failed\");\n\n const diagnostics = formatCommandFailure(tsError);\n\n if (diagnostics) {\n console.error(diagnostics);\n }\n\n process.exit(1);\n }\n\n const [structureCommand, ...structureArgs] =\n buildStructureCheckCommand(filePath);\n\n try {\n await execa(structureCommand, structureArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\n });\n } catch (structureError) {\n // The child reports the reason on stderr, which execa captures. Without\n // replaying it the user only ever sees the generic hint below, even when\n // the server file has an error they could act on.\n const reason = formatCommandFailure(structureError);\n\n if (reason) {\n console.error(reason);\n } else {\n console.error(\"[FastMCP] ✗ Server structure validation failed\");\n console.error(\n \"Make sure the file properly imports and uses FastMCP\",\n );\n }\n\n process.exit(1);\n }\n\n console.log(\n \"[FastMCP] ✓ All validations passed! Server file looks good.\",\n );\n } catch (error) {\n console.error(\n \"[FastMCP Error] Validation failed:\",\n error instanceof Error ? error.message : String(error),\n );\n\n process.exit(1);\n }\n },\n )\n\n .demandCommand(1)\n .strict()\n .help()\n .parseAsync();\n","export type DevCommandOptions = {\n /**\n * Path to a temporary mcp-cli config file that registers the dev server.\n * Only used in non-interactive mode (when `tool` is set).\n */\n configPath?: string;\n /**\n * Path to the server file to run.\n */\n file: string;\n /**\n * Name of the tool to call non-interactively. When omitted, the dev\n * command launches the interactive mcp-cli inspector instead.\n */\n tool?: string;\n /**\n * JSON string of arguments forwarded to the tool via mcp-cli `--args`.\n * Only used in non-interactive mode.\n */\n toolArgs?: string;\n /**\n * Watch the file for changes and restart the server. Only used in\n * interactive mode; a non-interactive call runs the server once.\n */\n watch?: boolean;\n};\n\n/**\n * The server name registered in the generated mcp-cli config. mcp-cli\n * addresses non-interactive targets as `<server-name>:<tool>`.\n */\nexport const DEV_SERVER_NAME = \"dev\";\n\n/**\n * Build the JSON config that registers the dev server with mcp-cli so it can\n * be invoked non-interactively. mcp-cli's non-interactive mode resolves the\n * server by name from a config file's `mcpServers` map, so an inline command\n * cannot be passed directly alongside `call-tool`.\n *\n * The server is never started in watch mode here: a non-interactive call\n * connects, calls one tool, and exits, so there is nothing to restart into.\n */\nexport const buildDevConfig = (file: string): string =>\n JSON.stringify(\n {\n mcpServers: {\n [DEV_SERVER_NAME]: {\n args: [\"tsx\", file],\n command: \"npx\",\n },\n },\n },\n null,\n 2,\n );\n\n/**\n * Build the argv that the dev command runs.\n *\n * This is an argv array rather than a shell string so that nothing has to be\n * quoted: file paths, tool names and JSON `--args` are passed to the child\n * process verbatim. Quoting through a shell would be wrong on Windows, where\n * cmd.exe treats single quotes as literal characters rather than as quoting.\n *\n * - Without `tool`: launches the interactive @wong2/mcp-cli inspector\n * against an inline `npx tsx <file>` server (existing behaviour).\n * - With `tool`: runs @wong2/mcp-cli in non-interactive mode against a\n * generated config file, calling the named tool and forwarding `--args`.\n */\nexport const buildDevCommand = (\n options: DevCommandOptions,\n): [string, ...string[]] => {\n const { configPath, file, tool, toolArgs, watch = false } = options;\n\n if (tool) {\n if (!configPath) {\n throw new Error(\n \"configPath is required when calling a tool non-interactively\",\n );\n }\n\n return [\n \"npx\",\n \"@wong2/mcp-cli\",\n \"-c\",\n configPath,\n \"call-tool\",\n `${DEV_SERVER_NAME}:${tool}`,\n ...(toolArgs === undefined ? [] : [\"--args\", toolArgs]),\n ];\n }\n\n return [\n \"npx\",\n \"@wong2/mcp-cli\",\n \"npx\",\n \"tsx\",\n ...(watch ? [\"--watch\"] : []),\n file,\n ];\n};\n","import { existsSync } from \"node:fs\";\nimport { rm, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\n/**\n * Compiler options for type-checking a server file with no `tsconfig.json`\n * above it. tsc's own defaults (ES5, CommonJS-era module resolution) cannot\n * even read FastMCP's declarations, which use private class fields and a\n * default import of `http`, so no real server file could pass under them.\n * These describe how a server actually runs instead: as an ES module on a\n * current Node, which can import `.ts` files directly.\n */\nexport const DEFAULT_TYPE_CHECK_OPTIONS = [\n \"--allowImportingTsExtensions\",\n \"--module\",\n \"esnext\",\n \"--moduleResolution\",\n \"bundler\",\n \"--skipLibCheck\",\n \"--target\",\n \"es2022\",\n];\n\n/**\n * The script that `fastmcp validate` runs to check a server file can be\n * imported.\n *\n * The target file is read from `process.argv[1]` instead of being spliced into\n * this source. Splicing is not equivalent: the path would land inside a\n * JavaScript string literal, so the child's own parser would consume the\n * backslashes of a Windows path as string escapes. `C:\\Users\\dev\\server.ts`\n * reaches the import as `C:Usersdevserver.ts`, which throws `ERR_INVALID_URL`\n * and is reported to the user as \"does not import FastMCP\" even though the file\n * is fine.\n *\n * The script exits explicitly once the import settles. Importing a server file\n * normally starts the server, and a running server — a stdio transport waiting\n * on stdin, an HTTP listener — keeps the process alive indefinitely, so\n * validating a server that calls `start()` would otherwise never finish.\n */\nexport const STRUCTURE_CHECK_SCRIPT = `\n(async () => {\n try {\n const { FastMCP } = await import(\"fastmcp\");\n await import(process.argv[1]);\n console.log(\"[FastMCP] ✓ Server structure validation passed\");\n } catch (error) {\n console.error(\"[FastMCP] ✗ Server structure validation failed:\", error.message);\n process.exitCode = 1;\n }\n\n process.exit();\n})();\n`;\n\n/**\n * Build the argv for the type-check step.\n *\n * This is an argv array rather than a shell string so that nothing has to be\n * quoted: the file path is passed to tsc verbatim, so a path containing spaces\n * stays one argument. Quoting through a shell would be wrong on Windows, where\n * cmd.exe re-parses the command line and splits such a path into several root\n * files.\n *\n * Given a `project` (see `withTypeCheckProject`), tsc checks the file through\n * it; without one, the file is passed directly with\n * `DEFAULT_TYPE_CHECK_OPTIONS`.\n */\nexport const buildTypeCheckCommand = (\n file: string,\n { project, strict = false }: { project?: string; strict?: boolean } = {},\n): [string, ...string[]] => [\n \"npx\",\n \"tsc\",\n \"--noEmit\",\n ...(strict ? [\"--strict\"] : []),\n ...(project ? [\"--project\", project] : [...DEFAULT_TYPE_CHECK_OPTIONS, file]),\n];\n\n/**\n * Build a tsconfig that checks only `file`, with the compiler options of the\n * project's own `tsconfig`.\n *\n * `tsc <file>` ignores tsconfig.json altogether and falls back to tsc's\n * defaults, while `tsc --project tsconfig.json` checks every file in the\n * project rather than the one being validated. Extending the project's config\n * and listing just `file` gets both right. A project that is `incremental` or\n * `composite` still writes a `.tsbuildinfo` under `--noEmit`, so both are\n * switched off: validating a file should leave the project untouched.\n */\nexport const buildTypeCheckProject = (tsconfig: string, file: string): string =>\n JSON.stringify({\n compilerOptions: { composite: false, incremental: false },\n extends: `./${basename(tsconfig)}`,\n files: [file],\n include: [],\n });\n\n/**\n * Find the `tsconfig.json` that applies to files in `dir`: the nearest one in\n * it or any of its parents, which is where tsc and editors look too.\n */\nexport const findTsconfig = (dir: string): string | undefined => {\n const candidate = join(dir, \"tsconfig.json\");\n\n if (existsSync(candidate)) {\n return candidate;\n }\n\n const parent = dirname(dir);\n\n return parent === dir ? undefined : findTsconfig(parent);\n};\n\n/**\n * Run `check` with a throwaway tsconfig for `file` (see\n * `buildTypeCheckProject`), or with no project when the file has no\n * `tsconfig.json` above it.\n *\n * The throwaway config is written next to the one it extends and removed once\n * `check` settles. It cannot live in a temporary directory: tsc looks for the\n * `@types` packages it includes by default relative to the config file, so\n * from anywhere else a server using, say, `process.env` would stop compiling.\n */\nexport const withTypeCheckProject = async <T>(\n file: string,\n check: (project?: string) => Promise<T>,\n): Promise<T> => {\n const tsconfig = findTsconfig(dirname(file));\n\n if (!tsconfig) {\n return check();\n }\n\n const project = join(\n dirname(tsconfig),\n `tsconfig.fastmcp-validate-${process.pid}.json`,\n );\n\n await writeFile(project, buildTypeCheckProject(tsconfig, file), \"utf8\");\n\n try {\n return await check(project);\n } finally {\n await rm(project, { force: true });\n }\n};\n\n/**\n * Build the argv for the structure-check step.\n *\n * As above, the file is passed as an argument rather than quoted into a shell\n * command. It is converted to a file URL by the parent process, so the child\n * receives the URL as-is and never has to reconstruct it. The child is the same\n * Node binary running the CLI, so no PATH lookup is involved.\n */\nexport const buildStructureCheckCommand = (\n file: string,\n execPath: string = process.execPath,\n): [string, ...string[]] => [\n execPath,\n \"-e\",\n STRUCTURE_CHECK_SCRIPT,\n pathToFileURL(file).href,\n];\n\n/**\n * The output streams a failed command carries. execa sets both on the error it\n * throws, but they are optional here so the extraction stays honest about not\n * every `Error` having them.\n */\ntype CommandOutputStreams = {\n stderr?: unknown;\n stdout?: unknown;\n};\n\nconst hasOutputStreams = (\n error: Error,\n): error is CommandOutputStreams & Error =>\n \"stdout\" in error || \"stderr\" in error;\n\n/**\n * Extract the output of a failed command.\n *\n * tsc writes its diagnostics to stdout, while a failure to launch the compiler\n * at all (a missing `npx`, for instance) reports on stderr — reading only\n * stderr left the message empty for every real type error. The structure check\n * reports the reason on stderr, which execa captures, so it has to be replayed\n * here as well or the caller can only print a generic hint.\n *\n * An error that did not come from a command at all — the throwaway tsconfig\n * could not be written, say — is reported by its message.\n */\nexport const formatCommandFailure = (error: unknown): string => {\n if (!(error instanceof Error)) {\n return \"\";\n }\n\n if (!hasOutputStreams(error)) {\n return error.message;\n }\n\n const collect = (value: unknown): string =>\n typeof value === \"string\" ? value.trim() : \"\";\n\n return [collect(error.stderr), collect(error.stdout)]\n .filter(Boolean)\n .join(\"\\n\");\n};\n"]}
@@ -318,5 +318,5 @@ await yargs(hideBin(process.argv)).scriptName("fastmcp").command(
318
318
  process.exit(1);
319
319
  }
320
320
  }
321
- ).help().parseAsync();
321
+ ).demandCommand(1).strict().help().parseAsync();
322
322
  //# sourceMappingURL=fastmcp.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/fastmcp.ts","../../src/bin/devCommand.ts","../../src/bin/validateCommand.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { execa } from \"execa\";\nimport { mkdtemp, rm, writeFile } from \"fs/promises\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nimport { buildDevCommand, buildDevConfig } from \"./devCommand.js\";\nimport {\n buildStructureCheckCommand,\n buildTypeCheckCommand,\n formatCommandFailure,\n withTypeCheckProject,\n} from \"./validateCommand.js\";\n\nawait yargs(hideBin(process.argv))\n .scriptName(\"fastmcp\")\n .command(\n \"dev <file>\",\n \"Start a development server\",\n (yargs) => {\n return yargs\n .positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n })\n\n .option(\"args\", {\n describe:\n \"JSON arguments passed to the tool (requires --tool), e.g. '{\\\"a\\\":1}'\",\n type: \"string\",\n })\n\n .option(\"tool\", {\n alias: \"t\",\n describe:\n \"Call a tool non-interactively instead of launching the inspector\",\n type: \"string\",\n })\n\n .option(\"watch\", {\n alias: \"w\",\n default: false,\n describe: \"Watch for file changes and restart server\",\n type: \"boolean\",\n })\n\n .option(\"verbose\", {\n alias: \"v\",\n default: false,\n describe: \"Enable verbose logging\",\n type: \"boolean\",\n });\n },\n\n async (argv) => {\n let configDir: string | undefined;\n\n try {\n if (argv.args !== undefined && !argv.tool) {\n console.error(\"[FastMCP Error] --args requires --tool\");\n process.exitCode = 1;\n return;\n }\n\n if (argv.tool && argv.watch) {\n console.warn(\n \"[FastMCP] --watch is ignored when calling a tool with --tool: the server runs for a single call.\",\n );\n }\n\n let configPath: string | undefined;\n\n if (argv.tool) {\n configDir = await mkdtemp(join(tmpdir(), \"fastmcp-dev-\"));\n configPath = join(configDir, \"mcp-cli.json\");\n await writeFile(configPath, buildDevConfig(argv.file), \"utf8\");\n }\n\n const [command, ...commandArgs] = buildDevCommand({\n configPath,\n file: argv.file,\n tool: argv.tool,\n toolArgs: argv.args,\n watch: argv.watch,\n });\n\n if (argv.verbose) {\n console.log(\n `[FastMCP] Starting server: ${[command, ...commandArgs].join(\" \")}`,\n );\n console.log(`[FastMCP] File: ${argv.file}`);\n console.log(\n `[FastMCP] Watch mode: ${argv.watch ? \"enabled\" : \"disabled\"}`,\n );\n\n if (argv.tool) {\n console.log(`[FastMCP] Tool: ${argv.tool}`);\n }\n }\n\n await execa(command, commandArgs, {\n stderr: \"inherit\",\n stdin: \"inherit\",\n stdout: \"inherit\",\n });\n } catch (error) {\n console.error(\n \"[FastMCP Error] Failed to start development server:\",\n error instanceof Error ? error.message : String(error),\n );\n\n if (argv.verbose && error instanceof Error && error.stack) {\n console.error(\"[FastMCP Debug] Stack trace:\", error.stack);\n }\n\n // Not process.exit(): that would skip the `finally` block below and\n // leak the temporary config directory on every failed tool call.\n process.exitCode = 1;\n } finally {\n if (configDir) {\n await rm(configDir, { force: true, recursive: true });\n }\n }\n },\n )\n\n .command(\n \"inspect <file>\",\n \"Inspect a server file\",\n (yargs) => {\n return yargs.positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n });\n },\n\n async (argv) => {\n try {\n await execa({\n stderr: \"inherit\",\n stdout: \"inherit\",\n })`npx @modelcontextprotocol/inspector npx tsx ${argv.file}`;\n } catch (error) {\n console.error(\n \"[FastMCP Error] Failed to inspect server:\",\n error instanceof Error ? error.message : String(error),\n );\n\n process.exit(1);\n }\n },\n )\n\n .command(\n \"validate <file>\",\n \"Validate a FastMCP server file for syntax and basic structure\",\n (yargs) => {\n return yargs\n .positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n })\n\n .option(\"strict\", {\n alias: \"s\",\n default: false,\n describe: \"Enable strict validation (type checking)\",\n type: \"boolean\",\n });\n },\n\n async (argv) => {\n try {\n const { existsSync } = await import(\"fs\");\n const { resolve } = await import(\"path\");\n const filePath = resolve(argv.file);\n\n if (!existsSync(filePath)) {\n console.error(`[FastMCP Error] File not found: ${filePath}`);\n process.exit(1);\n }\n\n console.log(`[FastMCP] Validating server file: ${filePath}`);\n\n try {\n await withTypeCheckProject(filePath, (project) => {\n const [typeCheckCommand, ...typeCheckArgs] = buildTypeCheckCommand(\n filePath,\n { project, strict: argv.strict },\n );\n\n return execa(typeCheckCommand, typeCheckArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\n });\n });\n\n console.log(\"[FastMCP] ✓ TypeScript compilation successful\");\n } catch (tsError) {\n console.error(\"[FastMCP] ✗ TypeScript compilation failed\");\n\n const diagnostics = formatCommandFailure(tsError);\n\n if (diagnostics) {\n console.error(diagnostics);\n }\n\n process.exit(1);\n }\n\n const [structureCommand, ...structureArgs] =\n buildStructureCheckCommand(filePath);\n\n try {\n await execa(structureCommand, structureArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\n });\n } catch (structureError) {\n // The child reports the reason on stderr, which execa captures. Without\n // replaying it the user only ever sees the generic hint below, even when\n // the server file has an error they could act on.\n const reason = formatCommandFailure(structureError);\n\n if (reason) {\n console.error(reason);\n } else {\n console.error(\"[FastMCP] ✗ Server structure validation failed\");\n console.error(\n \"Make sure the file properly imports and uses FastMCP\",\n );\n }\n\n process.exit(1);\n }\n\n console.log(\n \"[FastMCP] ✓ All validations passed! Server file looks good.\",\n );\n } catch (error) {\n console.error(\n \"[FastMCP Error] Validation failed:\",\n error instanceof Error ? error.message : String(error),\n );\n\n process.exit(1);\n }\n },\n )\n\n .help()\n .parseAsync();\n","export type DevCommandOptions = {\n /**\n * Path to a temporary mcp-cli config file that registers the dev server.\n * Only used in non-interactive mode (when `tool` is set).\n */\n configPath?: string;\n /**\n * Path to the server file to run.\n */\n file: string;\n /**\n * Name of the tool to call non-interactively. When omitted, the dev\n * command launches the interactive mcp-cli inspector instead.\n */\n tool?: string;\n /**\n * JSON string of arguments forwarded to the tool via mcp-cli `--args`.\n * Only used in non-interactive mode.\n */\n toolArgs?: string;\n /**\n * Watch the file for changes and restart the server. Only used in\n * interactive mode; a non-interactive call runs the server once.\n */\n watch?: boolean;\n};\n\n/**\n * The server name registered in the generated mcp-cli config. mcp-cli\n * addresses non-interactive targets as `<server-name>:<tool>`.\n */\nexport const DEV_SERVER_NAME = \"dev\";\n\n/**\n * Build the JSON config that registers the dev server with mcp-cli so it can\n * be invoked non-interactively. mcp-cli's non-interactive mode resolves the\n * server by name from a config file's `mcpServers` map, so an inline command\n * cannot be passed directly alongside `call-tool`.\n *\n * The server is never started in watch mode here: a non-interactive call\n * connects, calls one tool, and exits, so there is nothing to restart into.\n */\nexport const buildDevConfig = (file: string): string =>\n JSON.stringify(\n {\n mcpServers: {\n [DEV_SERVER_NAME]: {\n args: [\"tsx\", file],\n command: \"npx\",\n },\n },\n },\n null,\n 2,\n );\n\n/**\n * Build the argv that the dev command runs.\n *\n * This is an argv array rather than a shell string so that nothing has to be\n * quoted: file paths, tool names and JSON `--args` are passed to the child\n * process verbatim. Quoting through a shell would be wrong on Windows, where\n * cmd.exe treats single quotes as literal characters rather than as quoting.\n *\n * - Without `tool`: launches the interactive @wong2/mcp-cli inspector\n * against an inline `npx tsx <file>` server (existing behaviour).\n * - With `tool`: runs @wong2/mcp-cli in non-interactive mode against a\n * generated config file, calling the named tool and forwarding `--args`.\n */\nexport const buildDevCommand = (\n options: DevCommandOptions,\n): [string, ...string[]] => {\n const { configPath, file, tool, toolArgs, watch = false } = options;\n\n if (tool) {\n if (!configPath) {\n throw new Error(\n \"configPath is required when calling a tool non-interactively\",\n );\n }\n\n return [\n \"npx\",\n \"@wong2/mcp-cli\",\n \"-c\",\n configPath,\n \"call-tool\",\n `${DEV_SERVER_NAME}:${tool}`,\n ...(toolArgs === undefined ? [] : [\"--args\", toolArgs]),\n ];\n }\n\n return [\n \"npx\",\n \"@wong2/mcp-cli\",\n \"npx\",\n \"tsx\",\n ...(watch ? [\"--watch\"] : []),\n file,\n ];\n};\n","import { existsSync } from \"node:fs\";\nimport { rm, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\n/**\n * Compiler options for type-checking a server file with no `tsconfig.json`\n * above it. tsc's own defaults (ES5, CommonJS-era module resolution) cannot\n * even read FastMCP's declarations, which use private class fields and a\n * default import of `http`, so no real server file could pass under them.\n * These describe how a server actually runs instead: as an ES module on a\n * current Node, which can import `.ts` files directly.\n */\nexport const DEFAULT_TYPE_CHECK_OPTIONS = [\n \"--allowImportingTsExtensions\",\n \"--module\",\n \"esnext\",\n \"--moduleResolution\",\n \"bundler\",\n \"--skipLibCheck\",\n \"--target\",\n \"es2022\",\n];\n\n/**\n * The script that `fastmcp validate` runs to check a server file can be\n * imported.\n *\n * The target file is read from `process.argv[1]` instead of being spliced into\n * this source. Splicing is not equivalent: the path would land inside a\n * JavaScript string literal, so the child's own parser would consume the\n * backslashes of a Windows path as string escapes. `C:\\Users\\dev\\server.ts`\n * reaches the import as `C:Usersdevserver.ts`, which throws `ERR_INVALID_URL`\n * and is reported to the user as \"does not import FastMCP\" even though the file\n * is fine.\n *\n * The script exits explicitly once the import settles. Importing a server file\n * normally starts the server, and a running server — a stdio transport waiting\n * on stdin, an HTTP listener — keeps the process alive indefinitely, so\n * validating a server that calls `start()` would otherwise never finish.\n */\nexport const STRUCTURE_CHECK_SCRIPT = `\n(async () => {\n try {\n const { FastMCP } = await import(\"fastmcp\");\n await import(process.argv[1]);\n console.log(\"[FastMCP] ✓ Server structure validation passed\");\n } catch (error) {\n console.error(\"[FastMCP] ✗ Server structure validation failed:\", error.message);\n process.exitCode = 1;\n }\n\n process.exit();\n})();\n`;\n\n/**\n * Build the argv for the type-check step.\n *\n * This is an argv array rather than a shell string so that nothing has to be\n * quoted: the file path is passed to tsc verbatim, so a path containing spaces\n * stays one argument. Quoting through a shell would be wrong on Windows, where\n * cmd.exe re-parses the command line and splits such a path into several root\n * files.\n *\n * Given a `project` (see `withTypeCheckProject`), tsc checks the file through\n * it; without one, the file is passed directly with\n * `DEFAULT_TYPE_CHECK_OPTIONS`.\n */\nexport const buildTypeCheckCommand = (\n file: string,\n { project, strict = false }: { project?: string; strict?: boolean } = {},\n): [string, ...string[]] => [\n \"npx\",\n \"tsc\",\n \"--noEmit\",\n ...(strict ? [\"--strict\"] : []),\n ...(project ? [\"--project\", project] : [...DEFAULT_TYPE_CHECK_OPTIONS, file]),\n];\n\n/**\n * Build a tsconfig that checks only `file`, with the compiler options of the\n * project's own `tsconfig`.\n *\n * `tsc <file>` ignores tsconfig.json altogether and falls back to tsc's\n * defaults, while `tsc --project tsconfig.json` checks every file in the\n * project rather than the one being validated. Extending the project's config\n * and listing just `file` gets both right. A project that is `incremental` or\n * `composite` still writes a `.tsbuildinfo` under `--noEmit`, so both are\n * switched off: validating a file should leave the project untouched.\n */\nexport const buildTypeCheckProject = (tsconfig: string, file: string): string =>\n JSON.stringify({\n compilerOptions: { composite: false, incremental: false },\n extends: `./${basename(tsconfig)}`,\n files: [file],\n include: [],\n });\n\n/**\n * Find the `tsconfig.json` that applies to files in `dir`: the nearest one in\n * it or any of its parents, which is where tsc and editors look too.\n */\nexport const findTsconfig = (dir: string): string | undefined => {\n const candidate = join(dir, \"tsconfig.json\");\n\n if (existsSync(candidate)) {\n return candidate;\n }\n\n const parent = dirname(dir);\n\n return parent === dir ? undefined : findTsconfig(parent);\n};\n\n/**\n * Run `check` with a throwaway tsconfig for `file` (see\n * `buildTypeCheckProject`), or with no project when the file has no\n * `tsconfig.json` above it.\n *\n * The throwaway config is written next to the one it extends and removed once\n * `check` settles. It cannot live in a temporary directory: tsc looks for the\n * `@types` packages it includes by default relative to the config file, so\n * from anywhere else a server using, say, `process.env` would stop compiling.\n */\nexport const withTypeCheckProject = async <T>(\n file: string,\n check: (project?: string) => Promise<T>,\n): Promise<T> => {\n const tsconfig = findTsconfig(dirname(file));\n\n if (!tsconfig) {\n return check();\n }\n\n const project = join(\n dirname(tsconfig),\n `tsconfig.fastmcp-validate-${process.pid}.json`,\n );\n\n await writeFile(project, buildTypeCheckProject(tsconfig, file), \"utf8\");\n\n try {\n return await check(project);\n } finally {\n await rm(project, { force: true });\n }\n};\n\n/**\n * Build the argv for the structure-check step.\n *\n * As above, the file is passed as an argument rather than quoted into a shell\n * command. It is converted to a file URL by the parent process, so the child\n * receives the URL as-is and never has to reconstruct it. The child is the same\n * Node binary running the CLI, so no PATH lookup is involved.\n */\nexport const buildStructureCheckCommand = (\n file: string,\n execPath: string = process.execPath,\n): [string, ...string[]] => [\n execPath,\n \"-e\",\n STRUCTURE_CHECK_SCRIPT,\n pathToFileURL(file).href,\n];\n\n/**\n * The output streams a failed command carries. execa sets both on the error it\n * throws, but they are optional here so the extraction stays honest about not\n * every `Error` having them.\n */\ntype CommandOutputStreams = {\n stderr?: unknown;\n stdout?: unknown;\n};\n\nconst hasOutputStreams = (\n error: Error,\n): error is CommandOutputStreams & Error =>\n \"stdout\" in error || \"stderr\" in error;\n\n/**\n * Extract the output of a failed command.\n *\n * tsc writes its diagnostics to stdout, while a failure to launch the compiler\n * at all (a missing `npx`, for instance) reports on stderr — reading only\n * stderr left the message empty for every real type error. The structure check\n * reports the reason on stderr, which execa captures, so it has to be replayed\n * here as well or the caller can only print a generic hint.\n *\n * An error that did not come from a command at all — the throwaway tsconfig\n * could not be written, say — is reported by its message.\n */\nexport const formatCommandFailure = (error: unknown): string => {\n if (!(error instanceof Error)) {\n return \"\";\n }\n\n if (!hasOutputStreams(error)) {\n return error.message;\n }\n\n const collect = (value: unknown): string =>\n typeof value === \"string\" ? value.trim() : \"\";\n\n return [collect(error.stderr), collect(error.stdout)]\n .filter(Boolean)\n .join(\"\\n\");\n};\n"],"mappings":"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","names":["rm","writeFile","join","yargs","join","writeFile","rm","existsSync"]}
1
+ {"version":3,"sources":["../../src/bin/fastmcp.ts","../../src/bin/devCommand.ts","../../src/bin/validateCommand.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { execa } from \"execa\";\nimport { mkdtemp, rm, writeFile } from \"fs/promises\";\nimport { tmpdir } from \"os\";\nimport { join } from \"path\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\n\nimport { buildDevCommand, buildDevConfig } from \"./devCommand.js\";\nimport {\n buildStructureCheckCommand,\n buildTypeCheckCommand,\n formatCommandFailure,\n withTypeCheckProject,\n} from \"./validateCommand.js\";\n\nawait yargs(hideBin(process.argv))\n .scriptName(\"fastmcp\")\n .command(\n \"dev <file>\",\n \"Start a development server\",\n (yargs) => {\n return yargs\n .positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n })\n\n .option(\"args\", {\n describe:\n \"JSON arguments passed to the tool (requires --tool), e.g. '{\\\"a\\\":1}'\",\n type: \"string\",\n })\n\n .option(\"tool\", {\n alias: \"t\",\n describe:\n \"Call a tool non-interactively instead of launching the inspector\",\n type: \"string\",\n })\n\n .option(\"watch\", {\n alias: \"w\",\n default: false,\n describe: \"Watch for file changes and restart server\",\n type: \"boolean\",\n })\n\n .option(\"verbose\", {\n alias: \"v\",\n default: false,\n describe: \"Enable verbose logging\",\n type: \"boolean\",\n });\n },\n\n async (argv) => {\n let configDir: string | undefined;\n\n try {\n if (argv.args !== undefined && !argv.tool) {\n console.error(\"[FastMCP Error] --args requires --tool\");\n process.exitCode = 1;\n return;\n }\n\n if (argv.tool && argv.watch) {\n console.warn(\n \"[FastMCP] --watch is ignored when calling a tool with --tool: the server runs for a single call.\",\n );\n }\n\n let configPath: string | undefined;\n\n if (argv.tool) {\n configDir = await mkdtemp(join(tmpdir(), \"fastmcp-dev-\"));\n configPath = join(configDir, \"mcp-cli.json\");\n await writeFile(configPath, buildDevConfig(argv.file), \"utf8\");\n }\n\n const [command, ...commandArgs] = buildDevCommand({\n configPath,\n file: argv.file,\n tool: argv.tool,\n toolArgs: argv.args,\n watch: argv.watch,\n });\n\n if (argv.verbose) {\n console.log(\n `[FastMCP] Starting server: ${[command, ...commandArgs].join(\" \")}`,\n );\n console.log(`[FastMCP] File: ${argv.file}`);\n console.log(\n `[FastMCP] Watch mode: ${argv.watch ? \"enabled\" : \"disabled\"}`,\n );\n\n if (argv.tool) {\n console.log(`[FastMCP] Tool: ${argv.tool}`);\n }\n }\n\n await execa(command, commandArgs, {\n stderr: \"inherit\",\n stdin: \"inherit\",\n stdout: \"inherit\",\n });\n } catch (error) {\n console.error(\n \"[FastMCP Error] Failed to start development server:\",\n error instanceof Error ? error.message : String(error),\n );\n\n if (argv.verbose && error instanceof Error && error.stack) {\n console.error(\"[FastMCP Debug] Stack trace:\", error.stack);\n }\n\n // Not process.exit(): that would skip the `finally` block below and\n // leak the temporary config directory on every failed tool call.\n process.exitCode = 1;\n } finally {\n if (configDir) {\n await rm(configDir, { force: true, recursive: true });\n }\n }\n },\n )\n\n .command(\n \"inspect <file>\",\n \"Inspect a server file\",\n (yargs) => {\n return yargs.positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n });\n },\n\n async (argv) => {\n try {\n await execa({\n stderr: \"inherit\",\n stdout: \"inherit\",\n })`npx @modelcontextprotocol/inspector npx tsx ${argv.file}`;\n } catch (error) {\n console.error(\n \"[FastMCP Error] Failed to inspect server:\",\n error instanceof Error ? error.message : String(error),\n );\n\n process.exit(1);\n }\n },\n )\n\n .command(\n \"validate <file>\",\n \"Validate a FastMCP server file for syntax and basic structure\",\n (yargs) => {\n return yargs\n .positional(\"file\", {\n demandOption: true,\n describe: \"The path to the server file\",\n type: \"string\",\n })\n\n .option(\"strict\", {\n alias: \"s\",\n default: false,\n describe: \"Enable strict validation (type checking)\",\n type: \"boolean\",\n });\n },\n\n async (argv) => {\n try {\n const { existsSync } = await import(\"fs\");\n const { resolve } = await import(\"path\");\n const filePath = resolve(argv.file);\n\n if (!existsSync(filePath)) {\n console.error(`[FastMCP Error] File not found: ${filePath}`);\n process.exit(1);\n }\n\n console.log(`[FastMCP] Validating server file: ${filePath}`);\n\n try {\n await withTypeCheckProject(filePath, (project) => {\n const [typeCheckCommand, ...typeCheckArgs] = buildTypeCheckCommand(\n filePath,\n { project, strict: argv.strict },\n );\n\n return execa(typeCheckCommand, typeCheckArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\n });\n });\n\n console.log(\"[FastMCP] ✓ TypeScript compilation successful\");\n } catch (tsError) {\n console.error(\"[FastMCP] ✗ TypeScript compilation failed\");\n\n const diagnostics = formatCommandFailure(tsError);\n\n if (diagnostics) {\n console.error(diagnostics);\n }\n\n process.exit(1);\n }\n\n const [structureCommand, ...structureArgs] =\n buildStructureCheckCommand(filePath);\n\n try {\n await execa(structureCommand, structureArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\n });\n } catch (structureError) {\n // The child reports the reason on stderr, which execa captures. Without\n // replaying it the user only ever sees the generic hint below, even when\n // the server file has an error they could act on.\n const reason = formatCommandFailure(structureError);\n\n if (reason) {\n console.error(reason);\n } else {\n console.error(\"[FastMCP] ✗ Server structure validation failed\");\n console.error(\n \"Make sure the file properly imports and uses FastMCP\",\n );\n }\n\n process.exit(1);\n }\n\n console.log(\n \"[FastMCP] ✓ All validations passed! Server file looks good.\",\n );\n } catch (error) {\n console.error(\n \"[FastMCP Error] Validation failed:\",\n error instanceof Error ? error.message : String(error),\n );\n\n process.exit(1);\n }\n },\n )\n\n .demandCommand(1)\n .strict()\n .help()\n .parseAsync();\n","export type DevCommandOptions = {\n /**\n * Path to a temporary mcp-cli config file that registers the dev server.\n * Only used in non-interactive mode (when `tool` is set).\n */\n configPath?: string;\n /**\n * Path to the server file to run.\n */\n file: string;\n /**\n * Name of the tool to call non-interactively. When omitted, the dev\n * command launches the interactive mcp-cli inspector instead.\n */\n tool?: string;\n /**\n * JSON string of arguments forwarded to the tool via mcp-cli `--args`.\n * Only used in non-interactive mode.\n */\n toolArgs?: string;\n /**\n * Watch the file for changes and restart the server. Only used in\n * interactive mode; a non-interactive call runs the server once.\n */\n watch?: boolean;\n};\n\n/**\n * The server name registered in the generated mcp-cli config. mcp-cli\n * addresses non-interactive targets as `<server-name>:<tool>`.\n */\nexport const DEV_SERVER_NAME = \"dev\";\n\n/**\n * Build the JSON config that registers the dev server with mcp-cli so it can\n * be invoked non-interactively. mcp-cli's non-interactive mode resolves the\n * server by name from a config file's `mcpServers` map, so an inline command\n * cannot be passed directly alongside `call-tool`.\n *\n * The server is never started in watch mode here: a non-interactive call\n * connects, calls one tool, and exits, so there is nothing to restart into.\n */\nexport const buildDevConfig = (file: string): string =>\n JSON.stringify(\n {\n mcpServers: {\n [DEV_SERVER_NAME]: {\n args: [\"tsx\", file],\n command: \"npx\",\n },\n },\n },\n null,\n 2,\n );\n\n/**\n * Build the argv that the dev command runs.\n *\n * This is an argv array rather than a shell string so that nothing has to be\n * quoted: file paths, tool names and JSON `--args` are passed to the child\n * process verbatim. Quoting through a shell would be wrong on Windows, where\n * cmd.exe treats single quotes as literal characters rather than as quoting.\n *\n * - Without `tool`: launches the interactive @wong2/mcp-cli inspector\n * against an inline `npx tsx <file>` server (existing behaviour).\n * - With `tool`: runs @wong2/mcp-cli in non-interactive mode against a\n * generated config file, calling the named tool and forwarding `--args`.\n */\nexport const buildDevCommand = (\n options: DevCommandOptions,\n): [string, ...string[]] => {\n const { configPath, file, tool, toolArgs, watch = false } = options;\n\n if (tool) {\n if (!configPath) {\n throw new Error(\n \"configPath is required when calling a tool non-interactively\",\n );\n }\n\n return [\n \"npx\",\n \"@wong2/mcp-cli\",\n \"-c\",\n configPath,\n \"call-tool\",\n `${DEV_SERVER_NAME}:${tool}`,\n ...(toolArgs === undefined ? [] : [\"--args\", toolArgs]),\n ];\n }\n\n return [\n \"npx\",\n \"@wong2/mcp-cli\",\n \"npx\",\n \"tsx\",\n ...(watch ? [\"--watch\"] : []),\n file,\n ];\n};\n","import { existsSync } from \"node:fs\";\nimport { rm, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\n/**\n * Compiler options for type-checking a server file with no `tsconfig.json`\n * above it. tsc's own defaults (ES5, CommonJS-era module resolution) cannot\n * even read FastMCP's declarations, which use private class fields and a\n * default import of `http`, so no real server file could pass under them.\n * These describe how a server actually runs instead: as an ES module on a\n * current Node, which can import `.ts` files directly.\n */\nexport const DEFAULT_TYPE_CHECK_OPTIONS = [\n \"--allowImportingTsExtensions\",\n \"--module\",\n \"esnext\",\n \"--moduleResolution\",\n \"bundler\",\n \"--skipLibCheck\",\n \"--target\",\n \"es2022\",\n];\n\n/**\n * The script that `fastmcp validate` runs to check a server file can be\n * imported.\n *\n * The target file is read from `process.argv[1]` instead of being spliced into\n * this source. Splicing is not equivalent: the path would land inside a\n * JavaScript string literal, so the child's own parser would consume the\n * backslashes of a Windows path as string escapes. `C:\\Users\\dev\\server.ts`\n * reaches the import as `C:Usersdevserver.ts`, which throws `ERR_INVALID_URL`\n * and is reported to the user as \"does not import FastMCP\" even though the file\n * is fine.\n *\n * The script exits explicitly once the import settles. Importing a server file\n * normally starts the server, and a running server — a stdio transport waiting\n * on stdin, an HTTP listener — keeps the process alive indefinitely, so\n * validating a server that calls `start()` would otherwise never finish.\n */\nexport const STRUCTURE_CHECK_SCRIPT = `\n(async () => {\n try {\n const { FastMCP } = await import(\"fastmcp\");\n await import(process.argv[1]);\n console.log(\"[FastMCP] ✓ Server structure validation passed\");\n } catch (error) {\n console.error(\"[FastMCP] ✗ Server structure validation failed:\", error.message);\n process.exitCode = 1;\n }\n\n process.exit();\n})();\n`;\n\n/**\n * Build the argv for the type-check step.\n *\n * This is an argv array rather than a shell string so that nothing has to be\n * quoted: the file path is passed to tsc verbatim, so a path containing spaces\n * stays one argument. Quoting through a shell would be wrong on Windows, where\n * cmd.exe re-parses the command line and splits such a path into several root\n * files.\n *\n * Given a `project` (see `withTypeCheckProject`), tsc checks the file through\n * it; without one, the file is passed directly with\n * `DEFAULT_TYPE_CHECK_OPTIONS`.\n */\nexport const buildTypeCheckCommand = (\n file: string,\n { project, strict = false }: { project?: string; strict?: boolean } = {},\n): [string, ...string[]] => [\n \"npx\",\n \"tsc\",\n \"--noEmit\",\n ...(strict ? [\"--strict\"] : []),\n ...(project ? [\"--project\", project] : [...DEFAULT_TYPE_CHECK_OPTIONS, file]),\n];\n\n/**\n * Build a tsconfig that checks only `file`, with the compiler options of the\n * project's own `tsconfig`.\n *\n * `tsc <file>` ignores tsconfig.json altogether and falls back to tsc's\n * defaults, while `tsc --project tsconfig.json` checks every file in the\n * project rather than the one being validated. Extending the project's config\n * and listing just `file` gets both right. A project that is `incremental` or\n * `composite` still writes a `.tsbuildinfo` under `--noEmit`, so both are\n * switched off: validating a file should leave the project untouched.\n */\nexport const buildTypeCheckProject = (tsconfig: string, file: string): string =>\n JSON.stringify({\n compilerOptions: { composite: false, incremental: false },\n extends: `./${basename(tsconfig)}`,\n files: [file],\n include: [],\n });\n\n/**\n * Find the `tsconfig.json` that applies to files in `dir`: the nearest one in\n * it or any of its parents, which is where tsc and editors look too.\n */\nexport const findTsconfig = (dir: string): string | undefined => {\n const candidate = join(dir, \"tsconfig.json\");\n\n if (existsSync(candidate)) {\n return candidate;\n }\n\n const parent = dirname(dir);\n\n return parent === dir ? undefined : findTsconfig(parent);\n};\n\n/**\n * Run `check` with a throwaway tsconfig for `file` (see\n * `buildTypeCheckProject`), or with no project when the file has no\n * `tsconfig.json` above it.\n *\n * The throwaway config is written next to the one it extends and removed once\n * `check` settles. It cannot live in a temporary directory: tsc looks for the\n * `@types` packages it includes by default relative to the config file, so\n * from anywhere else a server using, say, `process.env` would stop compiling.\n */\nexport const withTypeCheckProject = async <T>(\n file: string,\n check: (project?: string) => Promise<T>,\n): Promise<T> => {\n const tsconfig = findTsconfig(dirname(file));\n\n if (!tsconfig) {\n return check();\n }\n\n const project = join(\n dirname(tsconfig),\n `tsconfig.fastmcp-validate-${process.pid}.json`,\n );\n\n await writeFile(project, buildTypeCheckProject(tsconfig, file), \"utf8\");\n\n try {\n return await check(project);\n } finally {\n await rm(project, { force: true });\n }\n};\n\n/**\n * Build the argv for the structure-check step.\n *\n * As above, the file is passed as an argument rather than quoted into a shell\n * command. It is converted to a file URL by the parent process, so the child\n * receives the URL as-is and never has to reconstruct it. The child is the same\n * Node binary running the CLI, so no PATH lookup is involved.\n */\nexport const buildStructureCheckCommand = (\n file: string,\n execPath: string = process.execPath,\n): [string, ...string[]] => [\n execPath,\n \"-e\",\n STRUCTURE_CHECK_SCRIPT,\n pathToFileURL(file).href,\n];\n\n/**\n * The output streams a failed command carries. execa sets both on the error it\n * throws, but they are optional here so the extraction stays honest about not\n * every `Error` having them.\n */\ntype CommandOutputStreams = {\n stderr?: unknown;\n stdout?: unknown;\n};\n\nconst hasOutputStreams = (\n error: Error,\n): error is CommandOutputStreams & Error =>\n \"stdout\" in error || \"stderr\" in error;\n\n/**\n * Extract the output of a failed command.\n *\n * tsc writes its diagnostics to stdout, while a failure to launch the compiler\n * at all (a missing `npx`, for instance) reports on stderr — reading only\n * stderr left the message empty for every real type error. The structure check\n * reports the reason on stderr, which execa captures, so it has to be replayed\n * here as well or the caller can only print a generic hint.\n *\n * An error that did not come from a command at all — the throwaway tsconfig\n * could not be written, say — is reported by its message.\n */\nexport const formatCommandFailure = (error: unknown): string => {\n if (!(error instanceof Error)) {\n return \"\";\n }\n\n if (!hasOutputStreams(error)) {\n return error.message;\n }\n\n const collect = (value: unknown): string =>\n typeof value === \"string\" ? value.trim() : \"\";\n\n return [collect(error.stderr), collect(error.stdout)]\n .filter(Boolean)\n .join(\"\\n\");\n};\n"],"mappings":"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","names":["rm","writeFile","join","yargs","join","writeFile","rm","existsSync"]}
@@ -668,10 +668,6 @@ var FastMCPSession = class extends FastMCPSessionEventEmitter {
668
668
  }
669
669
  }
670
670
  async close() {
671
- this.#connectionState = "closed";
672
- if (this.#pingInterval) {
673
- clearInterval(this.#pingInterval);
674
- }
675
671
  this.#abortSession();
676
672
  try {
677
673
  await this.#server.close();
@@ -828,11 +824,16 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
828
824
  });
829
825
  }
830
826
  /**
831
- * Cancels the `signal` held by every tool still executing on this session.
832
- * Idempotent, so the close path and the transport's own close handler can
833
- * both call it.
827
+ * Marks the session closed, stops pinging the client and cancels the
828
+ * `signal` held by every tool still executing on this session. Idempotent,
829
+ * so the close path and the transport's own close handler can both call it.
834
830
  */
835
831
  #abortSession() {
832
+ this.#connectionState = "closed";
833
+ if (this.#pingInterval) {
834
+ clearInterval(this.#pingInterval);
835
+ this.#pingInterval = null;
836
+ }
836
837
  if (!this.#abortController.signal.aborted) {
837
838
  this.#abortController.abort(new SessionError("Session closed"));
838
839
  }
@@ -996,6 +997,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
996
997
  break;
997
998
  }
998
999
  await delay(retryDelay);
1000
+ if (this.#connectionState === "closed") {
1001
+ return;
1002
+ }
999
1003
  }
1000
1004
  if (!this.#clientCapabilities) {
1001
1005
  this.#logger.warn(
@@ -1010,6 +1014,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1010
1014
  void this.#loadRoots(true);
1011
1015
  } else {
1012
1016
  await this.#loadRoots(false);
1017
+ if (this.#abortController.signal.aborted) {
1018
+ return;
1019
+ }
1013
1020
  }
1014
1021
  if (this.#clientCapabilities) {
1015
1022
  const pingConfig = this.#getPingConfig();
@@ -1728,7 +1735,15 @@ function joinPaths(basePath, path) {
1728
1735
  return `${basePath}${normalizePath(path)}`;
1729
1736
  }
1730
1737
  function matchUriTemplate(template, uri) {
1731
- const match = template.fromUri(uri);
1738
+ let match;
1739
+ try {
1740
+ match = template.fromUri(uri);
1741
+ } catch (error) {
1742
+ if (error instanceof URIError) {
1743
+ return void 0;
1744
+ }
1745
+ throw error;
1746
+ }
1732
1747
  if (!match) {
1733
1748
  return void 0;
1734
1749
  }
@@ -1764,6 +1779,35 @@ function parseBasicAuthHeader(authHeader) {
1764
1779
  return null;
1765
1780
  }
1766
1781
  }
1782
+ function parseBooleanSetting(value, source) {
1783
+ if (!value) {
1784
+ return void 0;
1785
+ }
1786
+ switch (value.toLowerCase()) {
1787
+ case "false":
1788
+ return false;
1789
+ case "true":
1790
+ return true;
1791
+ default:
1792
+ throw new Error(`${source} must be "true" or "false", got "${value}"`);
1793
+ }
1794
+ }
1795
+ function parseTransportSetting(value, source) {
1796
+ if (!value) {
1797
+ return void 0;
1798
+ }
1799
+ switch (value.toLowerCase()) {
1800
+ case "http-stream":
1801
+ case "httpstream":
1802
+ return "httpStream";
1803
+ case "stdio":
1804
+ return "stdio";
1805
+ default:
1806
+ throw new Error(
1807
+ `${source} must be "stdio", "httpStream" or "http-stream", got "${value}"`
1808
+ );
1809
+ }
1810
+ }
1767
1811
  function protectedResourceMetadataUrl(resource) {
1768
1812
  let url;
1769
1813
  try {
@@ -2971,8 +3015,17 @@ var FastMCP = class extends FastMCPEventEmitter {
2971
3015
  #parseRuntimeConfig(overrides) {
2972
3016
  const args = process.argv.slice(2);
2973
3017
  const getArg = (name) => {
2974
- const index = args.findIndex((arg) => arg === `--${name}`);
2975
- return index !== -1 && index + 1 < args.length ? args[index + 1] : void 0;
3018
+ const index = args.findIndex(
3019
+ (arg) => arg === `--${name}` || arg.startsWith(`--${name}=`)
3020
+ );
3021
+ if (index === -1) {
3022
+ return void 0;
3023
+ }
3024
+ if (args[index] !== `--${name}`) {
3025
+ return args[index].slice(name.length + 3);
3026
+ }
3027
+ const value = args[index + 1];
3028
+ return value === void 0 || value.startsWith("--") ? "" : value;
2976
3029
  };
2977
3030
  const transportArg = getArg("transport");
2978
3031
  const portArg = getArg("port");
@@ -2986,7 +3039,7 @@ var FastMCP = class extends FastMCPEventEmitter {
2986
3039
  const envBasePath = process.env.FASTMCP_BASE_PATH;
2987
3040
  const envStateless = process.env.FASTMCP_STATELESS;
2988
3041
  const envHost = process.env.FASTMCP_HOST;
2989
- const transportType = overrides?.transportType || (transportArg === "http-stream" ? "httpStream" : transportArg) || envTransport || "stdio";
3042
+ const transportType = overrides?.transportType || parseTransportSetting(transportArg, "--transport") || parseTransportSetting(envTransport, "FASTMCP_TRANSPORT") || "stdio";
2990
3043
  if (transportType === "httpStream") {
2991
3044
  const port = parseInt(
2992
3045
  overrides?.httpStream?.port?.toString() || portArg || envPort || "8080"
@@ -2997,7 +3050,8 @@ var FastMCP = class extends FastMCPEventEmitter {
2997
3050
  overrides?.httpStream?.basePath || basePathArg || envBasePath
2998
3051
  );
2999
3052
  const enableJsonResponse = overrides?.httpStream?.enableJsonResponse || false;
3000
- const stateless = overrides?.httpStream?.stateless ?? (statelessArg !== void 0 ? statelessArg === "true" : envStateless === "true");
3053
+ const stateless = overrides?.httpStream?.stateless ?? // A bare `--stateless` means `--stateless true`.
3054
+ (statelessArg === "" ? true : parseBooleanSetting(statelessArg, "--stateless")) ?? parseBooleanSetting(envStateless, "FASTMCP_STATELESS") ?? false;
3001
3055
  const cors = overrides?.httpStream?.cors;
3002
3056
  const eventStore = overrides?.httpStream?.eventStore;
3003
3057
  const sslCa = overrides?.httpStream?.sslCa;
@@ -3123,4 +3177,4 @@ export {
3123
3177
  FastMCPSession,
3124
3178
  FastMCP
3125
3179
  };
3126
- //# sourceMappingURL=chunk-NI4JFIL4.js.map
3180
+ //# sourceMappingURL=chunk-PVW7IVUE.js.map