UNPKG

fastmcp

Version:

A TypeScript framework for building MCP servers.

237 lines (235 loc) 7.62 kB
#!/usr/bin/env node "use strict"; function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // src/bin/fastmcp.ts var _execa = require('execa'); var _promises = require('fs/promises'); var _os = require('os'); var _path = require('path'); var _yargs = require('yargs'); var _yargs2 = _interopRequireDefault(_yargs); var _helpers = require('yargs/helpers'); // src/bin/devCommand.ts var DEV_SERVER_NAME = "dev"; var buildDevConfig = (file) => JSON.stringify( { mcpServers: { [DEV_SERVER_NAME]: { args: ["tsx", file], command: "npx" } } }, null, 2 ); var buildDevCommand = (options) => { const { configPath, file, tool, toolArgs, watch = false } = options; if (tool) { if (!configPath) { throw new Error( "configPath is required when calling a tool non-interactively" ); } return [ "npx", "@wong2/mcp-cli", "-c", configPath, "call-tool", `${DEV_SERVER_NAME}:${tool}`, ...toolArgs === void 0 ? [] : ["--args", toolArgs] ]; } return [ "npx", "@wong2/mcp-cli", "npx", "tsx", ...watch ? ["--watch"] : [], file ]; }; // src/bin/fastmcp.ts await _yargs2.default.call(void 0, _helpers.hideBin.call(void 0, process.argv)).scriptName("fastmcp").command( "dev <file>", "Start a development server", (yargs2) => { return yargs2.positional("file", { demandOption: true, describe: "The path to the server file", type: "string" }).option("args", { describe: `JSON arguments passed to the tool (requires --tool), e.g. '{"a":1}'`, type: "string" }).option("tool", { alias: "t", describe: "Call a tool non-interactively instead of launching the inspector", type: "string" }).option("watch", { alias: "w", default: false, describe: "Watch for file changes and restart server", type: "boolean" }).option("verbose", { alias: "v", default: false, describe: "Enable verbose logging", type: "boolean" }); }, async (argv) => { let configDir; try { if (argv.args !== void 0 && !argv.tool) { console.error("[FastMCP Error] --args requires --tool"); process.exitCode = 1; return; } if (argv.tool && argv.watch) { console.warn( "[FastMCP] --watch is ignored when calling a tool with --tool: the server runs for a single call." ); } let configPath; if (argv.tool) { configDir = await _promises.mkdtemp.call(void 0, _path.join.call(void 0, _os.tmpdir.call(void 0, ), "fastmcp-dev-")); configPath = _path.join.call(void 0, configDir, "mcp-cli.json"); await _promises.writeFile.call(void 0, configPath, buildDevConfig(argv.file), "utf8"); } const [command, ...commandArgs] = buildDevCommand({ configPath, file: argv.file, tool: argv.tool, toolArgs: argv.args, watch: argv.watch }); if (argv.verbose) { console.log( `[FastMCP] Starting server: ${[command, ...commandArgs].join(" ")}` ); console.log(`[FastMCP] File: ${argv.file}`); console.log( `[FastMCP] Watch mode: ${argv.watch ? "enabled" : "disabled"}` ); if (argv.tool) { console.log(`[FastMCP] Tool: ${argv.tool}`); } } await _execa.execa.call(void 0, command, commandArgs, { stderr: "inherit", stdin: "inherit", stdout: "inherit" }); } catch (error) { console.error( "[FastMCP Error] Failed to start development server:", error instanceof Error ? error.message : String(error) ); if (argv.verbose && error instanceof Error && error.stack) { console.error("[FastMCP Debug] Stack trace:", error.stack); } process.exitCode = 1; } finally { if (configDir) { await _promises.rm.call(void 0, configDir, { force: true, recursive: true }); } } } ).command( "inspect <file>", "Inspect a server file", (yargs2) => { return yargs2.positional("file", { demandOption: true, describe: "The path to the server file", type: "string" }); }, async (argv) => { try { await _execa.execa.call(void 0, { stderr: "inherit", stdout: "inherit" })`npx @modelcontextprotocol/inspector npx tsx ${argv.file}`; } catch (error) { console.error( "[FastMCP Error] Failed to inspect server:", error instanceof Error ? error.message : String(error) ); process.exit(1); } } ).command( "validate <file>", "Validate a FastMCP server file for syntax and basic structure", (yargs2) => { return yargs2.positional("file", { demandOption: true, describe: "The path to the server file", type: "string" }).option("strict", { alias: "s", default: false, describe: "Enable strict validation (type checking)", type: "boolean" }); }, async (argv) => { try { const { existsSync } = await Promise.resolve().then(() => _interopRequireWildcard(require("fs"))); const { resolve } = await Promise.resolve().then(() => _interopRequireWildcard(require("path"))); const filePath = resolve(argv.file); if (!existsSync(filePath)) { console.error(`[FastMCP Error] File not found: ${filePath}`); process.exit(1); } console.log(`[FastMCP] Validating server file: ${filePath}`); const command = argv.strict ? `npx tsc --noEmit --strict ${filePath}` : `npx tsc --noEmit ${filePath}`; try { await _execa.execa.call(void 0, { shell: true, stderr: "pipe", stdout: "pipe" })`${command}`; console.log("[FastMCP] \u2713 TypeScript compilation successful"); } catch (tsError) { console.error("[FastMCP] \u2717 TypeScript compilation failed"); if (tsError instanceof Error && "stderr" in tsError) { console.error(tsError.stderr); } process.exit(1); } try { await _execa.execa.call(void 0, { shell: true, stderr: "pipe", stdout: "pipe" })`node -e " (async () => { try { const { FastMCP } = await import('fastmcp'); await import('file://${filePath}'); console.log('[FastMCP] ✓ Server structure validation passed'); } catch (error) { console.error('[FastMCP] ✗ Server structure validation failed:', error.message); process.exit(1); } })(); "`; } catch (e) { console.error("[FastMCP] \u2717 Server structure validation failed"); console.error("Make sure the file properly imports and uses FastMCP"); process.exit(1); } console.log( "[FastMCP] \u2713 All validations passed! Server file looks good." ); } catch (error) { console.error( "[FastMCP Error] Validation failed:", error instanceof Error ? error.message : String(error) ); process.exit(1); } } ).help().parseAsync(); //# sourceMappingURL=fastmcp.cjs.map