fastmcp 4.20.15 → 4.20.17

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 _chunkCE5MU4DQcjs = require('./chunk-CE5MU4DQ.cjs');
14
+ var _chunk3V4NDT6Bcjs = require('./chunk-3V4NDT6B.cjs');
15
15
 
16
16
 
17
17
 
@@ -49,5 +49,5 @@ var _chunkBTXI2HQScjs = require('./chunk-BTXI2HQS.cjs');
49
49
 
50
50
 
51
51
 
52
- exports.AuthProvider = _chunkBTXI2HQScjs.AuthProvider; exports.AzureProvider = _chunkBTXI2HQScjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkCE5MU4DQcjs.DiscoveryDocumentCache; exports.FastMCP = _chunkCE5MU4DQcjs.FastMCP; exports.FastMCPError = _chunkCE5MU4DQcjs.FastMCPError; exports.FastMCPSession = _chunkCE5MU4DQcjs.FastMCPSession; exports.GitHubProvider = _chunkBTXI2HQScjs.GitHubProvider; exports.GoogleProvider = _chunkBTXI2HQScjs.GoogleProvider; exports.MEDIA_FETCH_TIMEOUT_MS = _chunkCE5MU4DQcjs.MEDIA_FETCH_TIMEOUT_MS; exports.OAuthProvider = _chunkBTXI2HQScjs.OAuthProvider; exports.ServerState = _chunkCE5MU4DQcjs.ServerState; exports.SessionError = _chunkCE5MU4DQcjs.SessionError; exports.UnexpectedStateError = _chunkCE5MU4DQcjs.UnexpectedStateError; exports.UserError = _chunkCE5MU4DQcjs.UserError; exports.audioContent = _chunkCE5MU4DQcjs.audioContent; exports.getAuthSession = _chunkBTXI2HQScjs.getAuthSession; exports.imageContent = _chunkCE5MU4DQcjs.imageContent; exports.jsonSchemaAdapter = _chunkCE5MU4DQcjs.jsonSchemaAdapter; exports.requireAll = _chunkBTXI2HQScjs.requireAll; exports.requireAny = _chunkBTXI2HQScjs.requireAny; exports.requireAuth = _chunkBTXI2HQScjs.requireAuth; exports.requireRole = _chunkBTXI2HQScjs.requireRole; exports.requireScopes = _chunkBTXI2HQScjs.requireScopes;
52
+ exports.AuthProvider = _chunkBTXI2HQScjs.AuthProvider; exports.AzureProvider = _chunkBTXI2HQScjs.AzureProvider; exports.DiscoveryDocumentCache = _chunk3V4NDT6Bcjs.DiscoveryDocumentCache; exports.FastMCP = _chunk3V4NDT6Bcjs.FastMCP; exports.FastMCPError = _chunk3V4NDT6Bcjs.FastMCPError; exports.FastMCPSession = _chunk3V4NDT6Bcjs.FastMCPSession; exports.GitHubProvider = _chunkBTXI2HQScjs.GitHubProvider; exports.GoogleProvider = _chunkBTXI2HQScjs.GoogleProvider; exports.MEDIA_FETCH_TIMEOUT_MS = _chunk3V4NDT6Bcjs.MEDIA_FETCH_TIMEOUT_MS; exports.OAuthProvider = _chunkBTXI2HQScjs.OAuthProvider; exports.ServerState = _chunk3V4NDT6Bcjs.ServerState; exports.SessionError = _chunk3V4NDT6Bcjs.SessionError; exports.UnexpectedStateError = _chunk3V4NDT6Bcjs.UnexpectedStateError; exports.UserError = _chunk3V4NDT6Bcjs.UserError; exports.audioContent = _chunk3V4NDT6Bcjs.audioContent; exports.getAuthSession = _chunkBTXI2HQScjs.getAuthSession; exports.imageContent = _chunk3V4NDT6Bcjs.imageContent; exports.jsonSchemaAdapter = _chunk3V4NDT6Bcjs.jsonSchemaAdapter; exports.requireAll = _chunkBTXI2HQScjs.requireAll; exports.requireAny = _chunkBTXI2HQScjs.requireAny; exports.requireAuth = _chunkBTXI2HQScjs.requireAuth; exports.requireRole = _chunkBTXI2HQScjs.requireRole; exports.requireScopes = _chunkBTXI2HQScjs.requireScopes;
53
53
  //# 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-ZNPHP74O.js";
14
+ } from "./chunk-XFDX4BNP.js";
15
15
  import {
16
16
  AuthProvider,
17
17
  AzureProvider,
@@ -50,6 +50,42 @@ var buildDevCommand = (options) => {
50
50
  ];
51
51
  };
52
52
 
53
+ // src/bin/validateCommand.ts
54
+ var _url = require('url');
55
+ var STRUCTURE_CHECK_SCRIPT = `
56
+ (async () => {
57
+ try {
58
+ const { FastMCP } = await import("fastmcp");
59
+ await import(process.argv[1]);
60
+ console.log("[FastMCP] \u2713 Server structure validation passed");
61
+ } catch (error) {
62
+ console.error("[FastMCP] \u2717 Server structure validation failed:", error.message);
63
+ process.exit(1);
64
+ }
65
+ })();
66
+ `;
67
+ var buildTypeCheckCommand = (file, strict = false) => [
68
+ "npx",
69
+ "tsc",
70
+ "--noEmit",
71
+ ...strict ? ["--strict"] : [],
72
+ file
73
+ ];
74
+ var buildStructureCheckCommand = (file, execPath = process.execPath) => [
75
+ execPath,
76
+ "-e",
77
+ STRUCTURE_CHECK_SCRIPT,
78
+ _url.pathToFileURL.call(void 0, file).href
79
+ ];
80
+ var hasOutputStreams = (error) => "stdout" in error || "stderr" in error;
81
+ var formatCommandFailure = (error) => {
82
+ if (!(error instanceof Error) || !hasOutputStreams(error)) {
83
+ return "";
84
+ }
85
+ const collect = (value) => typeof value === "string" ? value.trim() : "";
86
+ return [collect(error.stderr), collect(error.stdout)].filter(Boolean).join("\n");
87
+ };
88
+
53
89
  // src/bin/fastmcp.ts
54
90
  await _yargs2.default.call(void 0, _helpers.hideBin.call(void 0, process.argv)).scriptName("fastmcp").command(
55
91
  "dev <file>",
@@ -185,41 +221,40 @@ await _yargs2.default.call(void 0, _helpers.hideBin.call(void 0, process.argv)).
185
221
  process.exit(1);
186
222
  }
187
223
  console.log(`[FastMCP] Validating server file: ${filePath}`);
188
- const command = argv.strict ? `npx tsc --noEmit --strict ${filePath}` : `npx tsc --noEmit ${filePath}`;
224
+ const [typeCheckCommand, ...typeCheckArgs] = buildTypeCheckCommand(
225
+ filePath,
226
+ argv.strict
227
+ );
189
228
  try {
190
- await _execa.execa.call(void 0, {
191
- shell: true,
229
+ await _execa.execa.call(void 0, typeCheckCommand, typeCheckArgs, {
192
230
  stderr: "pipe",
193
231
  stdout: "pipe"
194
- })`${command}`;
232
+ });
195
233
  console.log("[FastMCP] \u2713 TypeScript compilation successful");
196
234
  } catch (tsError) {
197
235
  console.error("[FastMCP] \u2717 TypeScript compilation failed");
198
- if (tsError instanceof Error && "stderr" in tsError) {
199
- console.error(tsError.stderr);
236
+ const diagnostics = formatCommandFailure(tsError);
237
+ if (diagnostics) {
238
+ console.error(diagnostics);
200
239
  }
201
240
  process.exit(1);
202
241
  }
242
+ const [structureCommand, ...structureArgs] = buildStructureCheckCommand(filePath);
203
243
  try {
204
- await _execa.execa.call(void 0, {
205
- shell: true,
244
+ await _execa.execa.call(void 0, structureCommand, structureArgs, {
206
245
  stderr: "pipe",
207
246
  stdout: "pipe"
208
- })`node -e "
209
- (async () => {
210
- try {
211
- const { FastMCP } = await import('fastmcp');
212
- await import('file://${filePath}');
213
- console.log('[FastMCP] ✓ Server structure validation passed');
214
- } catch (error) {
215
- console.error('[FastMCP] ✗ Server structure validation failed:', error.message);
216
- process.exit(1);
217
- }
218
- })();
219
- "`;
220
- } catch (e) {
221
- console.error("[FastMCP] \u2717 Server structure validation failed");
222
- console.error("Make sure the file properly imports and uses FastMCP");
247
+ });
248
+ } catch (structureError) {
249
+ const reason = formatCommandFailure(structureError);
250
+ if (reason) {
251
+ console.error(reason);
252
+ } else {
253
+ console.error("[FastMCP] \u2717 Server structure validation failed");
254
+ console.error(
255
+ "Make sure the file properly imports and uses FastMCP"
256
+ );
257
+ }
223
258
  process.exit(1);
224
259
  }
225
260
  console.log(
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/bin/fastmcp.cjs","../../src/bin/fastmcp.ts","../../src/bin/devCommand.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\";\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 const command = argv.strict\n ? `npx tsc --noEmit --strict ${filePath}`\n : `npx tsc --noEmit ${filePath}`;\n\n try {\n await execa({\n shell: true,\n stderr: \"pipe\",\n stdout: \"pipe\",\n })`${command}`;\n\n console.log(\"[FastMCP] ✓ TypeScript compilation successful\");\n } catch (tsError) {\n console.error(\"[FastMCP] ✗ TypeScript compilation failed\");\n\n if (tsError instanceof Error && \"stderr\" in tsError) {\n console.error(tsError.stderr);\n }\n\n process.exit(1);\n }\n\n try {\n await execa({\n shell: true,\n stderr: \"pipe\",\n stdout: \"pipe\",\n })`node -e \"\n (async () => {\n try {\n const { FastMCP } = await import('fastmcp');\n await import('file://${filePath}');\n console.log('[FastMCP] ✓ Server structure validation passed');\n } catch (error) {\n console.error('[FastMCP] ✗ Server structure validation failed:', error.message);\n process.exit(1);\n }\n })();\n \"`;\n } catch {\n console.error(\"[FastMCP] ✗ Server structure validation failed\");\n console.error(\"Make sure the file properly imports and uses FastMCP\");\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"]}
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} 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 const [typeCheckCommand, ...typeCheckArgs] = buildTypeCheckCommand(\n filePath,\n argv.strict,\n );\n\n try {\n await execa(typeCheckCommand, typeCheckArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\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 { pathToFileURL } from \"node:url\";\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 */\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.exit(1);\n }\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 */\nexport const buildTypeCheckCommand = (\n file: string,\n strict = false,\n): [string, ...string[]] => [\n \"npx\",\n \"tsc\",\n \"--noEmit\",\n ...(strict ? [\"--strict\"] : []),\n file,\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 */\nexport const formatCommandFailure = (error: unknown): string => {\n if (!(error instanceof Error) || !hasOutputStreams(error)) {\n return \"\";\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"]}
@@ -50,6 +50,42 @@ var buildDevCommand = (options) => {
50
50
  ];
51
51
  };
52
52
 
53
+ // src/bin/validateCommand.ts
54
+ import { pathToFileURL } from "url";
55
+ var STRUCTURE_CHECK_SCRIPT = `
56
+ (async () => {
57
+ try {
58
+ const { FastMCP } = await import("fastmcp");
59
+ await import(process.argv[1]);
60
+ console.log("[FastMCP] \u2713 Server structure validation passed");
61
+ } catch (error) {
62
+ console.error("[FastMCP] \u2717 Server structure validation failed:", error.message);
63
+ process.exit(1);
64
+ }
65
+ })();
66
+ `;
67
+ var buildTypeCheckCommand = (file, strict = false) => [
68
+ "npx",
69
+ "tsc",
70
+ "--noEmit",
71
+ ...strict ? ["--strict"] : [],
72
+ file
73
+ ];
74
+ var buildStructureCheckCommand = (file, execPath = process.execPath) => [
75
+ execPath,
76
+ "-e",
77
+ STRUCTURE_CHECK_SCRIPT,
78
+ pathToFileURL(file).href
79
+ ];
80
+ var hasOutputStreams = (error) => "stdout" in error || "stderr" in error;
81
+ var formatCommandFailure = (error) => {
82
+ if (!(error instanceof Error) || !hasOutputStreams(error)) {
83
+ return "";
84
+ }
85
+ const collect = (value) => typeof value === "string" ? value.trim() : "";
86
+ return [collect(error.stderr), collect(error.stdout)].filter(Boolean).join("\n");
87
+ };
88
+
53
89
  // src/bin/fastmcp.ts
54
90
  await yargs(hideBin(process.argv)).scriptName("fastmcp").command(
55
91
  "dev <file>",
@@ -185,41 +221,40 @@ await yargs(hideBin(process.argv)).scriptName("fastmcp").command(
185
221
  process.exit(1);
186
222
  }
187
223
  console.log(`[FastMCP] Validating server file: ${filePath}`);
188
- const command = argv.strict ? `npx tsc --noEmit --strict ${filePath}` : `npx tsc --noEmit ${filePath}`;
224
+ const [typeCheckCommand, ...typeCheckArgs] = buildTypeCheckCommand(
225
+ filePath,
226
+ argv.strict
227
+ );
189
228
  try {
190
- await execa({
191
- shell: true,
229
+ await execa(typeCheckCommand, typeCheckArgs, {
192
230
  stderr: "pipe",
193
231
  stdout: "pipe"
194
- })`${command}`;
232
+ });
195
233
  console.log("[FastMCP] \u2713 TypeScript compilation successful");
196
234
  } catch (tsError) {
197
235
  console.error("[FastMCP] \u2717 TypeScript compilation failed");
198
- if (tsError instanceof Error && "stderr" in tsError) {
199
- console.error(tsError.stderr);
236
+ const diagnostics = formatCommandFailure(tsError);
237
+ if (diagnostics) {
238
+ console.error(diagnostics);
200
239
  }
201
240
  process.exit(1);
202
241
  }
242
+ const [structureCommand, ...structureArgs] = buildStructureCheckCommand(filePath);
203
243
  try {
204
- await execa({
205
- shell: true,
244
+ await execa(structureCommand, structureArgs, {
206
245
  stderr: "pipe",
207
246
  stdout: "pipe"
208
- })`node -e "
209
- (async () => {
210
- try {
211
- const { FastMCP } = await import('fastmcp');
212
- await import('file://${filePath}');
213
- console.log('[FastMCP] ✓ Server structure validation passed');
214
- } catch (error) {
215
- console.error('[FastMCP] ✗ Server structure validation failed:', error.message);
216
- process.exit(1);
217
- }
218
- })();
219
- "`;
220
- } catch {
221
- console.error("[FastMCP] \u2717 Server structure validation failed");
222
- console.error("Make sure the file properly imports and uses FastMCP");
247
+ });
248
+ } catch (structureError) {
249
+ const reason = formatCommandFailure(structureError);
250
+ if (reason) {
251
+ console.error(reason);
252
+ } else {
253
+ console.error("[FastMCP] \u2717 Server structure validation failed");
254
+ console.error(
255
+ "Make sure the file properly imports and uses FastMCP"
256
+ );
257
+ }
223
258
  process.exit(1);
224
259
  }
225
260
  console.log(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/bin/fastmcp.ts","../../src/bin/devCommand.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\";\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 const command = argv.strict\n ? `npx tsc --noEmit --strict ${filePath}`\n : `npx tsc --noEmit ${filePath}`;\n\n try {\n await execa({\n shell: true,\n stderr: \"pipe\",\n stdout: \"pipe\",\n })`${command}`;\n\n console.log(\"[FastMCP] ✓ TypeScript compilation successful\");\n } catch (tsError) {\n console.error(\"[FastMCP] ✗ TypeScript compilation failed\");\n\n if (tsError instanceof Error && \"stderr\" in tsError) {\n console.error(tsError.stderr);\n }\n\n process.exit(1);\n }\n\n try {\n await execa({\n shell: true,\n stderr: \"pipe\",\n stdout: \"pipe\",\n })`node -e \"\n (async () => {\n try {\n const { FastMCP } = await import('fastmcp');\n await import('file://${filePath}');\n console.log('[FastMCP] ✓ Server structure validation passed');\n } catch (error) {\n console.error('[FastMCP] ✗ Server structure validation failed:', error.message);\n process.exit(1);\n }\n })();\n \"`;\n } catch {\n console.error(\"[FastMCP] ✗ Server structure validation failed\");\n console.error(\"Make sure the file properly imports and uses FastMCP\");\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"],"mappings":";;;AAEA,SAAS,aAAa;AACtB,SAAS,SAAS,IAAI,iBAAiB;AACvC,SAAS,cAAc;AACvB,SAAS,YAAY;AACrB,OAAO,WAAW;AAClB,SAAS,eAAe;;;ACwBjB,IAAM,kBAAkB;AAWxB,IAAM,iBAAiB,CAAC,SAC7B,KAAK;AAAA,EACH;AAAA,IACE,YAAY;AAAA,MACV,CAAC,eAAe,GAAG;AAAA,QACjB,MAAM,CAAC,OAAO,IAAI;AAAA,QAClB,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,EACA;AACF;AAeK,IAAM,kBAAkB,CAC7B,YAC0B;AAC1B,QAAM,EAAE,YAAY,MAAM,MAAM,UAAU,QAAQ,MAAM,IAAI;AAE5D,MAAI,MAAM;AACR,QAAI,CAAC,YAAY;AACf,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAG,eAAe,IAAI,IAAI;AAAA,MAC1B,GAAI,aAAa,SAAY,CAAC,IAAI,CAAC,UAAU,QAAQ;AAAA,IACvD;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAI,QAAQ,CAAC,SAAS,IAAI,CAAC;AAAA,IAC3B;AAAA,EACF;AACF;;;ADzFA,MAAM,MAAM,QAAQ,QAAQ,IAAI,CAAC,EAC9B,WAAW,SAAS,EACpB;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAACA,WAAU;AACT,WAAOA,OACJ,WAAW,QAAQ;AAAA,MAClB,cAAc;AAAA,MACd,UAAU;AAAA,MACV,MAAM;AAAA,IACR,CAAC,EAEA,OAAO,QAAQ;AAAA,MACd,UACE;AAAA,MACF,MAAM;AAAA,IACR,CAAC,EAEA,OAAO,QAAQ;AAAA,MACd,OAAO;AAAA,MACP,UACE;AAAA,MACF,MAAM;AAAA,IACR,CAAC,EAEA,OAAO,SAAS;AAAA,MACf,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,MACV,MAAM;AAAA,IACR,CAAC,EAEA,OAAO,WAAW;AAAA,MACjB,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,MACV,MAAM;AAAA,IACR,CAAC;AAAA,EACL;AAAA,EAEA,OAAO,SAAS;AACd,QAAI;AAEJ,QAAI;AACF,UAAI,KAAK,SAAS,UAAa,CAAC,KAAK,MAAM;AACzC,gBAAQ,MAAM,wCAAwC;AACtD,gBAAQ,WAAW;AACnB;AAAA,MACF;AAEA,UAAI,KAAK,QAAQ,KAAK,OAAO;AAC3B,gBAAQ;AAAA,UACN;AAAA,QACF;AAAA,MACF;AAEA,UAAI;AAEJ,UAAI,KAAK,MAAM;AACb,oBAAY,MAAM,QAAQ,KAAK,OAAO,GAAG,cAAc,CAAC;AACxD,qBAAa,KAAK,WAAW,cAAc;AAC3C,cAAM,UAAU,YAAY,eAAe,KAAK,IAAI,GAAG,MAAM;AAAA,MAC/D;AAEA,YAAM,CAAC,SAAS,GAAG,WAAW,IAAI,gBAAgB;AAAA,QAChD;AAAA,QACA,MAAM,KAAK;AAAA,QACX,MAAM,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,OAAO,KAAK;AAAA,MACd,CAAC;AAED,UAAI,KAAK,SAAS;AAChB,gBAAQ;AAAA,UACN,8BAA8B,CAAC,SAAS,GAAG,WAAW,EAAE,KAAK,GAAG,CAAC;AAAA,QACnE;AACA,gBAAQ,IAAI,mBAAmB,KAAK,IAAI,EAAE;AAC1C,gBAAQ;AAAA,UACN,yBAAyB,KAAK,QAAQ,YAAY,UAAU;AAAA,QAC9D;AAEA,YAAI,KAAK,MAAM;AACb,kBAAQ,IAAI,mBAAmB,KAAK,IAAI,EAAE;AAAA,QAC5C;AAAA,MACF;AAEA,YAAM,MAAM,SAAS,aAAa;AAAA,QAChC,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,QAAQ;AAAA,MACV,CAAC;AAAA,IACH,SAAS,OAAO;AACd,cAAQ;AAAA,QACN;AAAA,QACA,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MACvD;AAEA,UAAI,KAAK,WAAW,iBAAiB,SAAS,MAAM,OAAO;AACzD,gBAAQ,MAAM,gCAAgC,MAAM,KAAK;AAAA,MAC3D;AAIA,cAAQ,WAAW;AAAA,IACrB,UAAE;AACA,UAAI,WAAW;AACb,cAAM,GAAG,WAAW,EAAE,OAAO,MAAM,WAAW,KAAK,CAAC;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AACF,EAEC;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAACA,WAAU;AACT,WAAOA,OAAM,WAAW,QAAQ;AAAA,MAC9B,cAAc;AAAA,MACd,UAAU;AAAA,MACV,MAAM;AAAA,IACR,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,SAAS;AACd,QAAI;AACF,YAAM,MAAM;AAAA,QACV,QAAQ;AAAA,QACR,QAAQ;AAAA,MACV,CAAC,gDAAgD,KAAK,IAAI;AAAA,IAC5D,SAAS,OAAO;AACd,cAAQ;AAAA,QACN;AAAA,QACA,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MACvD;AAEA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF,EAEC;AAAA,EACC;AAAA,EACA;AAAA,EACA,CAACA,WAAU;AACT,WAAOA,OACJ,WAAW,QAAQ;AAAA,MAClB,cAAc;AAAA,MACd,UAAU;AAAA,MACV,MAAM;AAAA,IACR,CAAC,EAEA,OAAO,UAAU;AAAA,MAChB,OAAO;AAAA,MACP,SAAS;AAAA,MACT,UAAU;AAAA,MACV,MAAM;AAAA,IACR,CAAC;AAAA,EACL;AAAA,EAEA,OAAO,SAAS;AACd,QAAI;AACF,YAAM,EAAE,WAAW,IAAI,MAAM,OAAO,IAAI;AACxC,YAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,MAAM;AACvC,YAAM,WAAW,QAAQ,KAAK,IAAI;AAElC,UAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,gBAAQ,MAAM,mCAAmC,QAAQ,EAAE;AAC3D,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,cAAQ,IAAI,qCAAqC,QAAQ,EAAE;AAE3D,YAAM,UAAU,KAAK,SACjB,6BAA6B,QAAQ,KACrC,oBAAoB,QAAQ;AAEhC,UAAI;AACF,cAAM,MAAM;AAAA,UACV,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,QAAQ;AAAA,QACV,CAAC,IAAI,OAAO;AAEZ,gBAAQ,IAAI,oDAA+C;AAAA,MAC7D,SAAS,SAAS;AAChB,gBAAQ,MAAM,gDAA2C;AAEzD,YAAI,mBAAmB,SAAS,YAAY,SAAS;AACnD,kBAAQ,MAAM,QAAQ,MAAM;AAAA,QAC9B;AAEA,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,UAAI;AACF,cAAM,MAAM;AAAA,UACV,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,QAAQ;AAAA,QACV,CAAC;AAAA;AAAA;AAAA;AAAA,uCAI4B,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQvC,QAAQ;AACN,gBAAQ,MAAM,qDAAgD;AAC9D,gBAAQ,MAAM,sDAAsD;AAEpE,gBAAQ,KAAK,CAAC;AAAA,MAChB;AAEA,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,cAAQ;AAAA,QACN;AAAA,QACA,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MACvD;AAEA,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACF,EAEC,KAAK,EACL,WAAW;","names":["yargs"]}
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} 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 const [typeCheckCommand, ...typeCheckArgs] = buildTypeCheckCommand(\n filePath,\n argv.strict,\n );\n\n try {\n await execa(typeCheckCommand, typeCheckArgs, {\n stderr: \"pipe\",\n stdout: \"pipe\",\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 { pathToFileURL } from \"node:url\";\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 */\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.exit(1);\n }\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 */\nexport const buildTypeCheckCommand = (\n file: string,\n strict = false,\n): [string, ...string[]] => [\n \"npx\",\n \"tsc\",\n \"--noEmit\",\n ...(strict ? [\"--strict\"] : []),\n file,\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 */\nexport const formatCommandFailure = (error: unknown): string => {\n if (!(error instanceof Error) || !hasOutputStreams(error)) {\n return \"\";\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":["yargs"]}
@@ -789,9 +789,9 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
789
789
  }
790
790
  }
791
791
  toolsListChanged(tools) {
792
- const allowedTools = tools.filter(
792
+ const allowedTools = this.#auth ? tools.filter(
793
793
  (tool) => tool.canAccess ? tool.canAccess(this.#auth) : true
794
- );
794
+ ) : tools;
795
795
  this.setupToolHandlers(allowedTools);
796
796
  this.triggerListChangedNotification("notifications/tools/list_changed");
797
797
  }
@@ -1162,7 +1162,7 @@ ${error instanceof Error ? error.stack : JSON.stringify(error)}`
1162
1162
  for (const arg of _nullishCoalesce(prompt.arguments, () => ( []))) {
1163
1163
  if (arg.required && !(args && arg.name in args)) {
1164
1164
  throw new (0, _typesjs.McpError)(
1165
- _typesjs.ErrorCode.InvalidRequest,
1165
+ _typesjs.ErrorCode.InvalidParams,
1166
1166
  `Prompt '${request.params.name}' requires argument '${arg.name}': ${arg.description || "No description provided"}`
1167
1167
  );
1168
1168
  }
@@ -2924,4 +2924,4 @@ var FastMCP = class extends FastMCPEventEmitter {
2924
2924
 
2925
2925
 
2926
2926
  exports.DiscoveryDocumentCache = DiscoveryDocumentCache; exports.jsonSchemaAdapter = jsonSchemaAdapter; exports.MEDIA_FETCH_TIMEOUT_MS = MEDIA_FETCH_TIMEOUT_MS; exports.imageContent = imageContent; exports.audioContent = audioContent; exports.FastMCPError = FastMCPError; exports.SessionError = SessionError; exports.UnexpectedStateError = UnexpectedStateError; exports.UserError = UserError; exports.ServerState = ServerState; exports.FastMCPSession = FastMCPSession; exports.FastMCP = FastMCP;
2927
- //# sourceMappingURL=chunk-CE5MU4DQ.cjs.map
2927
+ //# sourceMappingURL=chunk-3V4NDT6B.cjs.map