@prefecthq/fastmcp-ts 0.0.6 → 0.1.0

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.
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ // src/cli/entrypoint-runtime.ts
5
+ var import_node_url = require("url");
6
+ var AUTO_DETECT_NAMES = ["default", "mcp", "server", "app"];
7
+ function isFastMCPInstance(value) {
8
+ if (!value || typeof value !== "object") return false;
9
+ const obj = value;
10
+ return typeof obj["run"] === "function" && typeof obj["tool"] === "function" && typeof obj["resource"] === "function" && typeof obj["prompt"] === "function" && typeof obj["connect"] === "function";
11
+ }
12
+ function describe(value) {
13
+ if (value === null) return "null";
14
+ if (Array.isArray(value)) return "an array";
15
+ return `a ${typeof value}`;
16
+ }
17
+ function fail(message) {
18
+ console.error(`fastmcp: ${message}`);
19
+ process.exit(1);
20
+ }
21
+ async function resolveFactory(value, exportName, filePath) {
22
+ if (typeof value !== "function") return value;
23
+ try {
24
+ return await value();
25
+ } catch (err) {
26
+ fail(
27
+ `Failed to call entrypoint factory "${exportName}" in ${filePath}: ` + (err instanceof Error ? err.message : String(err))
28
+ );
29
+ }
30
+ }
31
+ async function main() {
32
+ const filePath = process.env["FASTMCP_ENTRYPOINT_FILE"];
33
+ if (!filePath) {
34
+ fail("internal error: FASTMCP_ENTRYPOINT_FILE was not set for the entrypoint bootstrap");
35
+ }
36
+ const explicitExport = process.env["FASTMCP_ENTRYPOINT_EXPORT"];
37
+ let mod;
38
+ try {
39
+ mod = await import((0, import_node_url.pathToFileURL)(filePath).href);
40
+ } catch (err) {
41
+ fail(
42
+ `Failed to load entrypoint file "${filePath}": ` + (err instanceof Error ? err.stack ?? err.message : String(err))
43
+ );
44
+ }
45
+ let resolved;
46
+ if (explicitExport) {
47
+ if (!(explicitExport in mod)) {
48
+ const available = Object.keys(mod).filter((k) => k !== "__esModule");
49
+ fail(
50
+ `Entrypoint export "${explicitExport}" not found in ${filePath}.` + (available.length > 0 ? ` Available exports: ${available.join(", ")}.` : " The file has no exports.")
51
+ );
52
+ }
53
+ const target = await resolveFactory(mod[explicitExport], explicitExport, filePath);
54
+ if (!isFastMCPInstance(target)) {
55
+ fail(
56
+ `Entrypoint export "${explicitExport}" in ${filePath} is not a FastMCP server (or a function that returns one). Got ${describe(target)}.`
57
+ );
58
+ }
59
+ resolved = target;
60
+ } else {
61
+ for (const name of AUTO_DETECT_NAMES) {
62
+ if (!(name in mod)) continue;
63
+ const candidate = mod[name];
64
+ if (isFastMCPInstance(candidate)) {
65
+ resolved = candidate;
66
+ break;
67
+ }
68
+ }
69
+ if (resolved === void 0) {
70
+ return;
71
+ }
72
+ }
73
+ if (resolved.isRunning) {
74
+ return;
75
+ }
76
+ await resolved.run();
77
+ if (resolved.address) {
78
+ const { host, port, path } = resolved.address;
79
+ process.stderr.write(`listening on http://${host}:${port}${path}
80
+ `);
81
+ }
82
+ }
83
+ main().catch((err) => {
84
+ console.error(err);
85
+ process.exit(1);
86
+ });
87
+ //# sourceMappingURL=entrypoint-runtime.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/entrypoint-runtime.ts"],"sourcesContent":["/**\n * Entrypoint bootstrap — spawned by the CLI (`run`, `inspect`, `list`, `call`,\n * `dev inspector`) instead of the user's server file directly.\n *\n * This mirrors Python FastMCP's `FileSystemSource` entrypoint resolution\n * (`fastmcp/utilities/mcp_server_config/v1/sources/filesystem.py`): import the\n * user's file, resolve a named export (or a factory function that returns a\n * server), and start it. Keeping this in a spawned subprocess (rather than\n * importing the user's file in the CLI's own process) preserves two things the\n * existing CLI already relies on: `tsx` transpilation for TypeScript files, and\n * process isolation so a crashing user server doesn't take down the CLI.\n *\n * Contract (set by the parent CLI process via environment variables):\n * - FASTMCP_ENTRYPOINT_FILE: absolute path to the user's server file (required)\n * - FASTMCP_ENTRYPOINT_EXPORT: export name to resolve. Omitted when the user\n * didn't specify one, in which case a conventional name is auto-detected.\n *\n * Resolution order when FASTMCP_ENTRYPOINT_EXPORT is not set:\n * `default`, `mcp`, `server`, `app` — the first of these that is already a\n * FastMCP instance wins. Auto-detection deliberately does NOT call factory\n * functions (mirroring Python FastMCP's `_find_server_object`, which only\n * resolves factories for an explicit entrypoint) — invoking an arbitrary\n * exported function as a side effect of guessing a name would be surprising,\n * and a name match that isn't a FastMCP instance is skipped in favor of the\n * next candidate rather than committing to it. Factory functions are only\n * resolved when the export name is given explicitly (`file:export` or\n * `--export`).\n *\n * Backwards compatibility: if no explicit export was requested and none of the\n * conventional names resolve to a valid entrypoint, this script assumes the\n * file already started its own server via top-level side effects (the\n * historical fastmcp-ts contract, e.g. `server.run()` at module scope) and\n * exits without error. An explicit export request that can't be resolved is\n * always a hard error.\n */\n\nimport { pathToFileURL } from 'node:url'\n\nconst AUTO_DETECT_NAMES = ['default', 'mcp', 'server', 'app']\n\ninterface RunnableFastMCP {\n run(): Promise<void>\n isRunning: boolean\n address: { host: string; port: number; path: string } | null\n}\n\nfunction isFastMCPInstance(value: unknown): value is RunnableFastMCP {\n if (!value || typeof value !== 'object') return false\n const obj = value as Record<string, unknown>\n return (\n typeof obj['run'] === 'function' &&\n typeof obj['tool'] === 'function' &&\n typeof obj['resource'] === 'function' &&\n typeof obj['prompt'] === 'function' &&\n typeof obj['connect'] === 'function'\n )\n}\n\nfunction describe(value: unknown): string {\n if (value === null) return 'null'\n if (Array.isArray(value)) return 'an array'\n return `a ${typeof value}`\n}\n\nfunction fail(message: string): never {\n console.error(`fastmcp: ${message}`)\n process.exit(1)\n}\n\nasync function resolveFactory(\n value: unknown,\n exportName: string,\n filePath: string,\n): Promise<unknown> {\n if (typeof value !== 'function') return value\n try {\n return await (value as () => unknown)()\n } catch (err) {\n fail(\n `Failed to call entrypoint factory \"${exportName}\" in ${filePath}: ` +\n (err instanceof Error ? err.message : String(err)),\n )\n }\n}\n\nasync function main(): Promise<void> {\n const filePath = process.env['FASTMCP_ENTRYPOINT_FILE']\n if (!filePath) {\n fail('internal error: FASTMCP_ENTRYPOINT_FILE was not set for the entrypoint bootstrap')\n }\n\n const explicitExport = process.env['FASTMCP_ENTRYPOINT_EXPORT']\n\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(filePath).href)) as Record<string, unknown>\n } catch (err) {\n fail(\n `Failed to load entrypoint file \"${filePath}\": ` +\n (err instanceof Error ? (err.stack ?? err.message) : String(err)),\n )\n }\n\n let resolved: RunnableFastMCP | undefined\n\n if (explicitExport) {\n if (!(explicitExport in mod)) {\n const available = Object.keys(mod).filter((k) => k !== '__esModule')\n fail(\n `Entrypoint export \"${explicitExport}\" not found in ${filePath}.` +\n (available.length > 0\n ? ` Available exports: ${available.join(', ')}.`\n : ' The file has no exports.'),\n )\n }\n const target = await resolveFactory(mod[explicitExport], explicitExport, filePath)\n if (!isFastMCPInstance(target)) {\n fail(\n `Entrypoint export \"${explicitExport}\" in ${filePath} is not a FastMCP server ` +\n `(or a function that returns one). Got ${describe(target)}.`,\n )\n }\n resolved = target\n } else {\n for (const name of AUTO_DETECT_NAMES) {\n if (!(name in mod)) continue\n const candidate = mod[name]\n // Only a direct FastMCP instance is auto-detected — a name match that\n // isn't one (including a function, which would require calling it) is\n // skipped in favor of the next conventional name rather than erroring\n // or invoking it speculatively.\n if (isFastMCPInstance(candidate)) {\n resolved = candidate\n break\n }\n }\n if (resolved === undefined) {\n // No conventional export resolved to a FastMCP instance. Assume this is\n // a legacy self-running file (it started its own server via top-level\n // side effects when imported above) and exit quietly.\n return\n }\n }\n\n if (resolved.isRunning) {\n // The file already started this server itself (e.g. a top-level\n // `server.run()` call) before we got a chance to. Don't start it twice.\n return\n }\n\n await resolved.run()\n\n // Mirrors the \"listening on <url>\" line the raw-SDK CLI test fixtures print\n // themselves — FastMCP's own run() doesn't emit a startup banner, but the\n // CLI's `run` command watches stderr for this text to detect a successful\n // HTTP start (see spawnServer()'s \"started\" detection in commands/run.ts).\n if (resolved.address) {\n const { host, port, path } = resolved.address\n process.stderr.write(`listening on http://${host}:${port}${path}\\n`)\n }\n}\n\nmain().catch((err) => {\n console.error(err)\n process.exit(1)\n})\n"],"mappings":";;;;AAoCA,sBAA8B;AAE9B,IAAM,oBAAoB,CAAC,WAAW,OAAO,UAAU,KAAK;AAQ5D,SAAS,kBAAkB,OAA0C;AACnE,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,QAAM,MAAM;AACZ,SACE,OAAO,IAAI,KAAK,MAAM,cACtB,OAAO,IAAI,MAAM,MAAM,cACvB,OAAO,IAAI,UAAU,MAAM,cAC3B,OAAO,IAAI,QAAQ,MAAM,cACzB,OAAO,IAAI,SAAS,MAAM;AAE9B;AAEA,SAAS,SAAS,OAAwB;AACxC,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO;AACjC,SAAO,KAAK,OAAO,KAAK;AAC1B;AAEA,SAAS,KAAK,SAAwB;AACpC,UAAQ,MAAM,YAAY,OAAO,EAAE;AACnC,UAAQ,KAAK,CAAC;AAChB;AAEA,eAAe,eACb,OACA,YACA,UACkB;AAClB,MAAI,OAAO,UAAU,WAAY,QAAO;AACxC,MAAI;AACF,WAAO,MAAO,MAAwB;AAAA,EACxC,SAAS,KAAK;AACZ;AAAA,MACE,sCAAsC,UAAU,QAAQ,QAAQ,QAC7D,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,IACpD;AAAA,EACF;AACF;AAEA,eAAe,OAAsB;AACnC,QAAM,WAAW,QAAQ,IAAI,yBAAyB;AACtD,MAAI,CAAC,UAAU;AACb,SAAK,kFAAkF;AAAA,EACzF;AAEA,QAAM,iBAAiB,QAAQ,IAAI,2BAA2B;AAE9D,MAAI;AACJ,MAAI;AACF,UAAO,MAAM,WAAO,+BAAc,QAAQ,EAAE;AAAA,EAC9C,SAAS,KAAK;AACZ;AAAA,MACE,mCAAmC,QAAQ,SACxC,eAAe,QAAS,IAAI,SAAS,IAAI,UAAW,OAAO,GAAG;AAAA,IACnE;AAAA,EACF;AAEA,MAAI;AAEJ,MAAI,gBAAgB;AAClB,QAAI,EAAE,kBAAkB,MAAM;AAC5B,YAAM,YAAY,OAAO,KAAK,GAAG,EAAE,OAAO,CAAC,MAAM,MAAM,YAAY;AACnE;AAAA,QACE,sBAAsB,cAAc,kBAAkB,QAAQ,OAC3D,UAAU,SAAS,IAChB,uBAAuB,UAAU,KAAK,IAAI,CAAC,MAC3C;AAAA,MACR;AAAA,IACF;AACA,UAAM,SAAS,MAAM,eAAe,IAAI,cAAc,GAAG,gBAAgB,QAAQ;AACjF,QAAI,CAAC,kBAAkB,MAAM,GAAG;AAC9B;AAAA,QACE,sBAAsB,cAAc,QAAQ,QAAQ,kEACT,SAAS,MAAM,CAAC;AAAA,MAC7D;AAAA,IACF;AACA,eAAW;AAAA,EACb,OAAO;AACL,eAAW,QAAQ,mBAAmB;AACpC,UAAI,EAAE,QAAQ,KAAM;AACpB,YAAM,YAAY,IAAI,IAAI;AAK1B,UAAI,kBAAkB,SAAS,GAAG;AAChC,mBAAW;AACX;AAAA,MACF;AAAA,IACF;AACA,QAAI,aAAa,QAAW;AAI1B;AAAA,IACF;AAAA,EACF;AAEA,MAAI,SAAS,WAAW;AAGtB;AAAA,EACF;AAEA,QAAM,SAAS,IAAI;AAMnB,MAAI,SAAS,SAAS;AACpB,UAAM,EAAE,MAAM,MAAM,KAAK,IAAI,SAAS;AACtC,YAAQ,OAAO,MAAM,uBAAuB,IAAI,IAAI,IAAI,GAAG,IAAI;AAAA,CAAI;AAAA,EACrE;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,UAAQ,MAAM,GAAG;AACjB,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":[]}
@@ -1172,7 +1172,7 @@ var init_version = __esm({
1172
1172
  async run({ args }) {
1173
1173
  if (args.json) setJsonMode(true);
1174
1174
  const data = {
1175
- fastmcp: "0.0.6",
1175
+ fastmcp: "0.1.0",
1176
1176
  "mcp-sdk": "^1.29.0",
1177
1177
  node: process.version,
1178
1178
  platform: `${process.platform} ${process.arch}`
@@ -1188,16 +1188,24 @@ var init_version = __esm({
1188
1188
  });
1189
1189
 
1190
1190
  // src/cli/utils/file-spec.ts
1191
- function parseFileSpec(spec) {
1191
+ function parseFileSpec(spec, exportOverride) {
1192
1192
  const colonIdx = spec.lastIndexOf(":");
1193
1193
  let filePart;
1194
1194
  let exportName;
1195
+ let explicitExport;
1195
1196
  if (colonIdx > 1) {
1196
1197
  filePart = spec.slice(0, colonIdx);
1197
- exportName = spec.slice(colonIdx + 1) || "default";
1198
+ exportName = spec.slice(colonIdx + 1);
1199
+ explicitExport = exportName.length > 0;
1200
+ if (!explicitExport) exportName = "default";
1198
1201
  } else {
1199
1202
  filePart = spec;
1200
1203
  exportName = "default";
1204
+ explicitExport = false;
1205
+ }
1206
+ if (exportOverride) {
1207
+ exportName = exportOverride;
1208
+ explicitExport = true;
1201
1209
  }
1202
1210
  const filePath = (0, import_node_path.resolve)(process.cwd(), filePart);
1203
1211
  if (!(0, import_node_fs.existsSync)(filePath)) {
@@ -1205,7 +1213,7 @@ function parseFileSpec(spec) {
1205
1213
  }
1206
1214
  const ext = (0, import_node_path.extname)(filePath).toLowerCase();
1207
1215
  const isTypeScript = ext === ".ts" || ext === ".tsx" || ext === ".mts";
1208
- return { filePath, exportName, isTypeScript };
1216
+ return { filePath, exportName, explicitExport, isTypeScript };
1209
1217
  }
1210
1218
  var import_node_fs, import_node_path;
1211
1219
  var init_file_spec = __esm({
@@ -1216,6 +1224,27 @@ var init_file_spec = __esm({
1216
1224
  }
1217
1225
  });
1218
1226
 
1227
+ // src/cli/utils/entrypoint-bootstrap.ts
1228
+ function resolveEntrypointBootstrapPath() {
1229
+ return (0, import_node_path2.join)(__dirname, "entrypoint-runtime.cjs");
1230
+ }
1231
+ function buildEntrypointEnv(spec) {
1232
+ const env2 = {
1233
+ FASTMCP_ENTRYPOINT_FILE: spec.filePath
1234
+ };
1235
+ if (spec.explicitExport) {
1236
+ env2["FASTMCP_ENTRYPOINT_EXPORT"] = spec.exportName;
1237
+ }
1238
+ return env2;
1239
+ }
1240
+ var import_node_path2;
1241
+ var init_entrypoint_bootstrap = __esm({
1242
+ "src/cli/utils/entrypoint-bootstrap.ts"() {
1243
+ "use strict";
1244
+ import_node_path2 = require("path");
1245
+ }
1246
+ });
1247
+
1219
1248
  // src/cli/utils/error.ts
1220
1249
  function cliError(message, opts = {}) {
1221
1250
  process.stderr.write(`${theme.error(symbols.failure)} ${theme.error(message)}
@@ -1274,12 +1303,12 @@ function readdirp(root, options = {}) {
1274
1303
  options.root = root;
1275
1304
  return new ReaddirpStream(options);
1276
1305
  }
1277
- var import_promises, import_node_path2, import_node_stream, EntryTypes, defaultOptions, RECURSIVE_ERROR_CODE, NORMAL_FLOW_ERRORS, ALL_TYPES, DIR_TYPES, FILE_TYPES, isNormalFlowError, wantBigintFsStats, emptyFn, normalizeFilter, ReaddirpStream;
1306
+ var import_promises, import_node_path3, import_node_stream, EntryTypes, defaultOptions, RECURSIVE_ERROR_CODE, NORMAL_FLOW_ERRORS, ALL_TYPES, DIR_TYPES, FILE_TYPES, isNormalFlowError, wantBigintFsStats, emptyFn, normalizeFilter, ReaddirpStream;
1278
1307
  var init_readdirp = __esm({
1279
1308
  "node_modules/readdirp/index.js"() {
1280
1309
  "use strict";
1281
1310
  import_promises = require("fs/promises");
1282
- import_node_path2 = require("path");
1311
+ import_node_path3 = require("path");
1283
1312
  import_node_stream = require("stream");
1284
1313
  EntryTypes = {
1285
1314
  FILE_TYPE: "files",
@@ -1369,7 +1398,7 @@ var init_readdirp = __esm({
1369
1398
  this._wantsDir = type ? DIR_TYPES.has(type) : false;
1370
1399
  this._wantsFile = type ? FILE_TYPES.has(type) : false;
1371
1400
  this._wantsEverything = type === EntryTypes.EVERYTHING_TYPE;
1372
- this._root = (0, import_node_path2.resolve)(root);
1401
+ this._root = (0, import_node_path3.resolve)(root);
1373
1402
  this._isDirent = !opts.alwaysStat;
1374
1403
  this._statsProp = this._isDirent ? "dirent" : "stats";
1375
1404
  this._rdOptions = { encoding: "utf8", withFileTypes: this._isDirent };
@@ -1440,8 +1469,8 @@ var init_readdirp = __esm({
1440
1469
  let entry;
1441
1470
  const basename3 = this._isDirent ? dirent.name : dirent;
1442
1471
  try {
1443
- const fullPath = (0, import_node_path2.resolve)((0, import_node_path2.join)(path, basename3));
1444
- entry = { path: (0, import_node_path2.relative)(this._root, fullPath), fullPath, basename: basename3 };
1472
+ const fullPath = (0, import_node_path3.resolve)((0, import_node_path3.join)(path, basename3));
1473
+ entry = { path: (0, import_node_path3.relative)(this._root, fullPath), fullPath, basename: basename3 };
1445
1474
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
1446
1475
  } catch (err) {
1447
1476
  this._onError(err);
@@ -1475,7 +1504,7 @@ var init_readdirp = __esm({
1475
1504
  }
1476
1505
  if (entryRealPathStats.isDirectory()) {
1477
1506
  const len = entryRealPath.length;
1478
- if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path2.sep) {
1507
+ if (full.startsWith(entryRealPath) && full.substr(len, 1) === import_node_path3.sep) {
1479
1508
  const recursiveError = new Error(`Circular symlink detected: "${full}" points to "${entryRealPath}"`);
1480
1509
  recursiveError.code = RECURSIVE_ERROR_CODE;
1481
1510
  return this._onError(recursiveError);
@@ -3019,10 +3048,11 @@ var run_exports = {};
3019
3048
  __export(run_exports, {
3020
3049
  default: () => run_default
3021
3050
  });
3022
- function spawnServer(filePath, isTypeScript, env2) {
3023
- const [cmd, args] = isTypeScript ? ["npx", ["tsx", filePath]] : ["node", [filePath]];
3051
+ function spawnServer(spec, env2) {
3052
+ const bootstrapPath = resolveEntrypointBootstrapPath();
3053
+ const [cmd, args] = spec.isTypeScript ? ["npx", ["tsx", bootstrapPath]] : ["node", [bootstrapPath]];
3024
3054
  return (0, import_node_child_process.spawn)(cmd, args, {
3025
- env: { ...process.env, ...env2 },
3055
+ env: { ...process.env, ...buildEntrypointEnv(spec), ...env2 },
3026
3056
  stdio: ["inherit", "pipe", "pipe"]
3027
3057
  });
3028
3058
  }
@@ -3033,6 +3063,7 @@ var init_run = __esm({
3033
3063
  init_dist();
3034
3064
  import_node_child_process = require("child_process");
3035
3065
  init_file_spec();
3066
+ init_entrypoint_bootstrap();
3036
3067
  init_error();
3037
3068
  init_theme();
3038
3069
  init_symbols();
@@ -3041,7 +3072,9 @@ var init_run = __esm({
3041
3072
  args: {
3042
3073
  spec: { type: "positional", description: "File spec (e.g. server.ts or server.ts:app)", required: true },
3043
3074
  transport: { type: "string", description: "Transport type (stdio|http|sse)", default: "stdio" },
3075
+ host: { type: "string", description: "HTTP host to bind to (for http transport)" },
3044
3076
  port: { type: "string", description: "HTTP port (for http/sse transports)" },
3077
+ path: { type: "string", description: "HTTP path to serve on (for http transport)" },
3045
3078
  reload: { type: "boolean", description: "Restart on file change", default: false }
3046
3079
  },
3047
3080
  async run({ args }) {
@@ -3054,8 +3087,10 @@ var init_run = __esm({
3054
3087
  const transportEnv = {
3055
3088
  MCP_TRANSPORT: args.transport
3056
3089
  };
3090
+ if (args.host) transportEnv["MCP_HOST"] = args.host;
3057
3091
  if (args.port) transportEnv["MCP_PORT"] = args.port;
3058
- let child = spawnServer(fileSpec.filePath, fileSpec.isTypeScript, transportEnv);
3092
+ if (args.path) transportEnv["MCP_PATH"] = args.path;
3093
+ let child = spawnServer(fileSpec, transportEnv);
3059
3094
  let started = false;
3060
3095
  function attachHandlers(proc) {
3061
3096
  proc.stdout?.on("data", (chunk) => {
@@ -3091,7 +3126,7 @@ var init_run = __esm({
3091
3126
  `);
3092
3127
  child.kill();
3093
3128
  started = false;
3094
- child = spawnServer(fileSpec.filePath, fileSpec.isTypeScript, transportEnv);
3129
+ child = spawnServer(fileSpec, transportEnv);
3095
3130
  attachHandlers(child);
3096
3131
  });
3097
3132
  }
@@ -29381,8 +29416,11 @@ async function connectClient(mode, auth2) {
29381
29416
  return client2;
29382
29417
  }
29383
29418
  const { spec } = mode;
29384
- const [command, cmdArgs] = spec.isTypeScript ? ["npx", ["tsx", spec.filePath]] : ["node", [spec.filePath]];
29385
- const transport = new StdioTransport(command, cmdArgs, { env: stdioEnv });
29419
+ const bootstrapPath = resolveEntrypointBootstrapPath();
29420
+ const [command, cmdArgs] = spec.isTypeScript ? ["npx", ["tsx", bootstrapPath]] : ["node", [bootstrapPath]];
29421
+ const transport = new StdioTransport(command, cmdArgs, {
29422
+ env: { ...stdioEnv, ...buildEntrypointEnv(spec) }
29423
+ });
29386
29424
  const client = new Client2(transport, { auth: auth2 });
29387
29425
  await client.connect();
29388
29426
  return client;
@@ -29401,6 +29439,7 @@ var init_connect = __esm({
29401
29439
  "use strict";
29402
29440
  init_client3();
29403
29441
  init_transports();
29442
+ init_entrypoint_bootstrap();
29404
29443
  }
29405
29444
  });
29406
29445
 
@@ -30087,7 +30126,7 @@ var init_dist6 = __esm({
30087
30126
  function Ze() {
30088
30127
  return import_node_process4.default.platform !== "win32" ? import_node_process4.default.env.TERM !== "linux" : !!import_node_process4.default.env.CI || !!import_node_process4.default.env.WT_SESSION || !!import_node_process4.default.env.TERMINUS_SUBLIME || import_node_process4.default.env.ConEmuTask === "{cmd::Cmder}" || import_node_process4.default.env.TERM_PROGRAM === "Terminus-Sublime" || import_node_process4.default.env.TERM_PROGRAM === "vscode" || import_node_process4.default.env.TERM === "xterm-256color" || import_node_process4.default.env.TERM === "alacritty" || import_node_process4.default.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
30089
30128
  }
30090
- var import_node_util3, import_node_process4, import_node_fs4, import_node_path3, import_sisteransi2, ee, ae, w2, _e, oe, ue, F, le, d, E2, Ie, Ee, z3, H2, te, U, J, xe, se, ce, Ge, $e, de, Oe, he, pe, me, ge, V2, ot2, Ct, fe, Ve, je;
30129
+ var import_node_util3, import_node_process4, import_node_fs4, import_node_path4, import_sisteransi2, ee, ae, w2, _e, oe, ue, F, le, d, E2, Ie, Ee, z3, H2, te, U, J, xe, se, ce, Ge, $e, de, Oe, he, pe, me, ge, V2, ot2, Ct, fe, Ve, je;
30091
30130
  var init_dist7 = __esm({
30092
30131
  "node_modules/@clack/prompts/dist/index.mjs"() {
30093
30132
  "use strict";
@@ -30098,7 +30137,7 @@ var init_dist7 = __esm({
30098
30137
  init_main();
30099
30138
  init_dist5();
30100
30139
  import_node_fs4 = require("fs");
30101
- import_node_path3 = require("path");
30140
+ import_node_path4 = require("path");
30102
30141
  import_sisteransi2 = __toESM(require_src(), 1);
30103
30142
  ee = Ze();
30104
30143
  ae = () => process.env.CI === "true";
@@ -32121,6 +32160,7 @@ var init_inspect = __esm({
32121
32160
  url: { type: "string", description: "Server URL" },
32122
32161
  command: { type: "string", description: "stdio server command" },
32123
32162
  file: { type: "string", description: "Server file (e.g. server.ts)" },
32163
+ export: { type: "string", description: "Named export to resolve (e.g. server); overrides file:export syntax" },
32124
32164
  auth: { type: "string", description: "Bearer token" },
32125
32165
  json: { type: "boolean", description: "Output JSON", default: false }
32126
32166
  },
@@ -32133,7 +32173,7 @@ var init_inspect = __esm({
32133
32173
  let fileSpec;
32134
32174
  if (args.file) {
32135
32175
  try {
32136
- fileSpec = parseFileSpec(args.file);
32176
+ fileSpec = parseFileSpec(args.file, args.export);
32137
32177
  } catch (err) {
32138
32178
  cliError(formatError(err));
32139
32179
  }
@@ -32234,6 +32274,7 @@ var init_list = __esm({
32234
32274
  url: { type: "string", description: "Server URL" },
32235
32275
  command: { type: "string", description: "stdio server command" },
32236
32276
  file: { type: "string", description: "Server file (e.g. server.ts)" },
32277
+ export: { type: "string", description: "Named export to resolve (e.g. server); overrides file:export syntax" },
32237
32278
  auth: { type: "string", description: "Bearer token" },
32238
32279
  resources: { type: "boolean", description: "Also list resources", default: false },
32239
32280
  prompts: { type: "boolean", description: "Also list prompts", default: false },
@@ -32249,7 +32290,7 @@ var init_list = __esm({
32249
32290
  let fileSpec;
32250
32291
  if (args.file) {
32251
32292
  try {
32252
- fileSpec = parseFileSpec(args.file);
32293
+ fileSpec = parseFileSpec(args.file, args.export);
32253
32294
  } catch (err) {
32254
32295
  cliError(formatError(err));
32255
32296
  }
@@ -32524,6 +32565,7 @@ var init_call = __esm({
32524
32565
  url: { type: "string", description: "Server URL" },
32525
32566
  command: { type: "string", description: "stdio server command" },
32526
32567
  file: { type: "string", description: "Server file (e.g. server.ts)" },
32568
+ export: { type: "string", description: "Named export to resolve (e.g. server); overrides file:export syntax" },
32527
32569
  auth: { type: "string", description: "Bearer token" },
32528
32570
  "input-json": { type: "string", description: "Raw JSON input instead of key=value args" },
32529
32571
  json: { type: "boolean", description: "Output JSON", default: false }
@@ -32537,7 +32579,7 @@ var init_call = __esm({
32537
32579
  let fileSpec;
32538
32580
  if (args.file) {
32539
32581
  try {
32540
- fileSpec = parseFileSpec(args.file);
32582
+ fileSpec = parseFileSpec(args.file, args.export);
32541
32583
  } catch (err) {
32542
32584
  cliError(formatError(err));
32543
32585
  }
@@ -32573,7 +32615,7 @@ var init_call = __esm({
32573
32615
  { hint: suggestion ? `Did you mean "${suggestion}"?` : void 0 }
32574
32616
  );
32575
32617
  }
32576
- const flagValues = new Set([target, args.url, args.command, args.file, args.auth, args["input-json"]].filter(Boolean));
32618
+ const flagValues = new Set([target, args.url, args.command, args.file, args.export, args.auth, args["input-json"]].filter(Boolean));
32577
32619
  const kvRaw = rawArgs.filter((a) => !a.startsWith("-") && !flagValues.has(a));
32578
32620
  let input = args["input-json"] ? JSON.parse(args["input-json"]) : parseKvArgs(kvRaw);
32579
32621
  if (matchedTool?.inputSchema) {
@@ -39939,11 +39981,11 @@ var require_dist2 = __commonJS({
39939
39981
  function getConfigPaths() {
39940
39982
  const home = (0, import_node_os3.homedir)();
39941
39983
  const platform2 = process.platform;
39942
- const claudeDesktop = platform2 === "darwin" ? (0, import_node_path4.join)(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : platform2 === "win32" ? (0, import_node_path4.join)(process.env["APPDATA"] ?? (0, import_node_path4.join)(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json") : (0, import_node_path4.join)(home, ".config", "Claude", "claude_desktop_config.json");
39984
+ const claudeDesktop = platform2 === "darwin" ? (0, import_node_path5.join)(home, "Library", "Application Support", "Claude", "claude_desktop_config.json") : platform2 === "win32" ? (0, import_node_path5.join)(process.env["APPDATA"] ?? (0, import_node_path5.join)(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json") : (0, import_node_path5.join)(home, ".config", "Claude", "claude_desktop_config.json");
39943
39985
  return {
39944
39986
  "claude-code": {
39945
39987
  name: "claude-code",
39946
- path: (0, import_node_path4.join)(home, ".claude.json"),
39988
+ path: (0, import_node_path5.join)(home, ".claude.json"),
39947
39989
  format: "json"
39948
39990
  },
39949
39991
  "claude-desktop": {
@@ -39953,22 +39995,22 @@ function getConfigPaths() {
39953
39995
  },
39954
39996
  cursor: {
39955
39997
  name: "cursor",
39956
- path: (0, import_node_path4.join)(home, ".cursor", "mcp.json"),
39998
+ path: (0, import_node_path5.join)(home, ".cursor", "mcp.json"),
39957
39999
  format: "json"
39958
40000
  },
39959
40001
  gemini: {
39960
40002
  name: "gemini",
39961
- path: (0, import_node_path4.join)(home, ".gemini", "settings.json"),
40003
+ path: (0, import_node_path5.join)(home, ".gemini", "settings.json"),
39962
40004
  format: "json"
39963
40005
  },
39964
40006
  goose: {
39965
40007
  name: "goose",
39966
- path: (0, import_node_path4.join)(home, ".config", "goose", "config.yaml"),
40008
+ path: (0, import_node_path5.join)(home, ".config", "goose", "config.yaml"),
39967
40009
  format: "yaml"
39968
40010
  },
39969
40011
  "mcp-json": {
39970
40012
  name: "mcp-json",
39971
- path: (0, import_node_path4.resolve)(process.cwd(), "mcp.json"),
40013
+ path: (0, import_node_path5.resolve)(process.cwd(), "mcp.json"),
39972
40014
  format: "json"
39973
40015
  }
39974
40016
  };
@@ -39982,12 +40024,12 @@ function writeConfig(path, data, format2) {
39982
40024
  const content = format2 === "yaml" ? import_yaml.default.stringify(data) : JSON.stringify(data, null, 2) + "\n";
39983
40025
  (0, import_node_fs5.writeFileSync)(path, content, "utf8");
39984
40026
  }
39985
- var import_node_os3, import_node_path4, import_node_fs5, import_yaml;
40027
+ var import_node_os3, import_node_path5, import_node_fs5, import_yaml;
39986
40028
  var init_config_paths = __esm({
39987
40029
  "src/cli/utils/config-paths.ts"() {
39988
40030
  "use strict";
39989
40031
  import_node_os3 = require("os");
39990
- import_node_path4 = require("path");
40032
+ import_node_path5 = require("path");
39991
40033
  import_node_fs5 = require("fs");
39992
40034
  import_yaml = __toESM(require_dist2(), 1);
39993
40035
  }
@@ -45169,7 +45211,7 @@ function parseEnvMap(raw) {
45169
45211
  );
45170
45212
  }
45171
45213
  function ensureDir(path) {
45172
- const dir = (0, import_node_path5.dirname)(path);
45214
+ const dir = (0, import_node_path6.dirname)(path);
45173
45215
  if (!(0, import_node_fs6.existsSync)(dir)) {
45174
45216
  (0, import_node_fs6.mkdirSync)(dir, { recursive: true });
45175
45217
  }
@@ -45256,12 +45298,12 @@ async function installServer(opts) {
45256
45298
  cliError(err instanceof Error ? err.message : String(err));
45257
45299
  }
45258
45300
  }
45259
- var import_node_fs6, import_node_path5;
45301
+ var import_node_fs6, import_node_path6;
45260
45302
  var init_shared = __esm({
45261
45303
  "src/cli/commands/install/shared.ts"() {
45262
45304
  "use strict";
45263
45305
  import_node_fs6 = require("fs");
45264
- import_node_path5 = require("path");
45306
+ import_node_path6 = require("path");
45265
45307
  init_dist8();
45266
45308
  init_dist7();
45267
45309
  init_config_paths();
@@ -45550,6 +45592,7 @@ var init_inspector = __esm({
45550
45592
  init_dist();
45551
45593
  import_node_child_process2 = require("child_process");
45552
45594
  init_file_spec();
45595
+ init_entrypoint_bootstrap();
45553
45596
  init_error();
45554
45597
  init_output();
45555
45598
  init_theme();
@@ -45568,7 +45611,8 @@ var init_inspector = __esm({
45568
45611
  } catch (err) {
45569
45612
  cliError(formatError(err));
45570
45613
  }
45571
- const serverCmd = fileSpec.isTypeScript ? `npx tsx ${fileSpec.filePath}` : `node ${fileSpec.filePath}`;
45614
+ const bootstrapPath = resolveEntrypointBootstrapPath();
45615
+ const serverCmd = fileSpec.isTypeScript ? `npx tsx ${bootstrapPath}` : `node ${bootstrapPath}`;
45572
45616
  await withSpinner(
45573
45617
  "Starting inspector\u2026",
45574
45618
  () => new Promise((resolve5) => setTimeout(resolve5, 300))
@@ -45576,7 +45620,11 @@ var init_inspector = __esm({
45576
45620
  const inspectorProcess = (0, import_node_child_process2.spawn)(
45577
45621
  "npx",
45578
45622
  ["@modelcontextprotocol/inspector", "--server", serverCmd],
45579
- { stdio: "inherit", shell: true, env: { ...process.env, MCP_TRANSPORT: "stdio" } }
45623
+ {
45624
+ stdio: "inherit",
45625
+ shell: true,
45626
+ env: { ...process.env, MCP_TRANSPORT: "stdio", ...buildEntrypointEnv(fileSpec) }
45627
+ }
45580
45628
  );
45581
45629
  log.info(`Inspector running \u2014 ${theme.url(`http://localhost:${args.port}`)}`);
45582
45630
  const { watch: watch2 } = await Promise.resolve().then(() => (init_chokidar(), chokidar_exports));
@@ -45623,7 +45671,7 @@ init_format();
45623
45671
  var main = defineCommand({
45624
45672
  meta: {
45625
45673
  name: "fastmcp",
45626
- version: "0.0.6",
45674
+ version: "0.1.0",
45627
45675
  description: "FastMCP CLI \u2014 build, run, and manage MCP servers"
45628
45676
  },
45629
45677
  args: {