fastmcp 4.8.0 → 4.9.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.
- package/README.md +8 -0
- package/dist/FastMCP.cjs +2 -2
- package/dist/FastMCP.js +1 -1
- package/dist/bin/fastmcp.cjs +91 -6
- package/dist/bin/fastmcp.cjs.map +1 -1
- package/dist/bin/fastmcp.js +91 -6
- package/dist/bin/fastmcp.js.map +1 -1
- package/dist/{chunk-JEOCXSB4.js → chunk-2PFUZL7I.js} +16 -1
- package/dist/{chunk-JEOCXSB4.js.map → chunk-2PFUZL7I.js.map} +1 -1
- package/dist/{chunk-GDMWRPPB.cjs → chunk-MJCWKCHZ.cjs} +16 -1
- package/dist/chunk-MJCWKCHZ.cjs.map +1 -0
- package/dist/examples/custom-routes.cjs +2 -2
- package/dist/examples/custom-routes.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-GDMWRPPB.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -2471,6 +2471,14 @@ npx fastmcp dev server.ts
|
|
|
2471
2471
|
|
|
2472
2472
|
This will run your server with [`mcp-cli`](https://github.com/wong2/mcp-cli) for testing and debugging your MCP server in the terminal.
|
|
2473
2473
|
|
|
2474
|
+
To call a tool non-interactively (for example, in scripts or automated tests), pass `--tool` and optional JSON `--args`:
|
|
2475
|
+
|
|
2476
|
+
```bash
|
|
2477
|
+
npx fastmcp dev server.ts --tool add --args '{"a":1,"b":2}'
|
|
2478
|
+
```
|
|
2479
|
+
|
|
2480
|
+
This prints the tool result as JSON and exits, instead of opening the interactive inspector. `--watch` has no effect in this mode, since the server is started for a single call.
|
|
2481
|
+
|
|
2474
2482
|
### Inspect with `MCP Inspector`
|
|
2475
2483
|
|
|
2476
2484
|
Another way is to use the official [`MCP Inspector`](https://modelcontextprotocol.io/docs/tools/inspector) to inspect your server with a Web UI:
|
package/dist/FastMCP.cjs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkMJCWKCHZcjs = require('./chunk-MJCWKCHZ.cjs');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
@@ -41,5 +41,5 @@ var _chunkIX3HKAX4cjs = require('./chunk-IX3HKAX4.cjs');
|
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
exports.AuthProvider = _chunkIX3HKAX4cjs.AuthProvider; exports.AzureProvider = _chunkIX3HKAX4cjs.AzureProvider; exports.DiscoveryDocumentCache =
|
|
44
|
+
exports.AuthProvider = _chunkIX3HKAX4cjs.AuthProvider; exports.AzureProvider = _chunkIX3HKAX4cjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkMJCWKCHZcjs.DiscoveryDocumentCache; exports.FastMCP = _chunkMJCWKCHZcjs.FastMCP; exports.FastMCPSession = _chunkMJCWKCHZcjs.FastMCPSession; exports.GitHubProvider = _chunkIX3HKAX4cjs.GitHubProvider; exports.GoogleProvider = _chunkIX3HKAX4cjs.GoogleProvider; exports.OAuthProvider = _chunkIX3HKAX4cjs.OAuthProvider; exports.ServerState = _chunkMJCWKCHZcjs.ServerState; exports.UnexpectedStateError = _chunkMJCWKCHZcjs.UnexpectedStateError; exports.UserError = _chunkMJCWKCHZcjs.UserError; exports.audioContent = _chunkMJCWKCHZcjs.audioContent; exports.getAuthSession = _chunkIX3HKAX4cjs.getAuthSession; exports.imageContent = _chunkMJCWKCHZcjs.imageContent; exports.requireAll = _chunkIX3HKAX4cjs.requireAll; exports.requireAny = _chunkIX3HKAX4cjs.requireAny; exports.requireAuth = _chunkIX3HKAX4cjs.requireAuth; exports.requireRole = _chunkIX3HKAX4cjs.requireRole; exports.requireScopes = _chunkIX3HKAX4cjs.requireScopes;
|
|
45
45
|
//# sourceMappingURL=FastMCP.cjs.map
|
package/dist/FastMCP.js
CHANGED
package/dist/bin/fastmcp.cjs
CHANGED
|
@@ -2,8 +2,55 @@
|
|
|
2
2
|
"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 }; }
|
|
3
3
|
// src/bin/fastmcp.ts
|
|
4
4
|
var _execa = require('execa');
|
|
5
|
+
var _promises = require('fs/promises');
|
|
6
|
+
var _os = require('os');
|
|
7
|
+
var _path = require('path');
|
|
5
8
|
var _yargs = require('yargs'); var _yargs2 = _interopRequireDefault(_yargs);
|
|
6
9
|
var _helpers = require('yargs/helpers');
|
|
10
|
+
|
|
11
|
+
// src/bin/devCommand.ts
|
|
12
|
+
var DEV_SERVER_NAME = "dev";
|
|
13
|
+
var buildDevConfig = (file) => JSON.stringify(
|
|
14
|
+
{
|
|
15
|
+
mcpServers: {
|
|
16
|
+
[DEV_SERVER_NAME]: {
|
|
17
|
+
args: ["tsx", file],
|
|
18
|
+
command: "npx"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
null,
|
|
23
|
+
2
|
|
24
|
+
);
|
|
25
|
+
var buildDevCommand = (options) => {
|
|
26
|
+
const { configPath, file, tool, toolArgs, watch = false } = options;
|
|
27
|
+
if (tool) {
|
|
28
|
+
if (!configPath) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"configPath is required when calling a tool non-interactively"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return [
|
|
34
|
+
"npx",
|
|
35
|
+
"@wong2/mcp-cli",
|
|
36
|
+
"-c",
|
|
37
|
+
configPath,
|
|
38
|
+
"call-tool",
|
|
39
|
+
`${DEV_SERVER_NAME}:${tool}`,
|
|
40
|
+
...toolArgs === void 0 ? [] : ["--args", toolArgs]
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
return [
|
|
44
|
+
"npx",
|
|
45
|
+
"@wong2/mcp-cli",
|
|
46
|
+
"npx",
|
|
47
|
+
"tsx",
|
|
48
|
+
...watch ? ["--watch"] : [],
|
|
49
|
+
file
|
|
50
|
+
];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// src/bin/fastmcp.ts
|
|
7
54
|
await _yargs2.default.call(void 0, _helpers.hideBin.call(void 0, process.argv)).scriptName("fastmcp").command(
|
|
8
55
|
"dev <file>",
|
|
9
56
|
"Start a development server",
|
|
@@ -12,6 +59,13 @@ await _yargs2.default.call(void 0, _helpers.hideBin.call(void 0, process.argv)).
|
|
|
12
59
|
demandOption: true,
|
|
13
60
|
describe: "The path to the server file",
|
|
14
61
|
type: "string"
|
|
62
|
+
}).option("args", {
|
|
63
|
+
describe: `JSON arguments passed to the tool (requires --tool), e.g. '{"a":1}'`,
|
|
64
|
+
type: "string"
|
|
65
|
+
}).option("tool", {
|
|
66
|
+
alias: "t",
|
|
67
|
+
describe: "Call a tool non-interactively instead of launching the inspector",
|
|
68
|
+
type: "string"
|
|
15
69
|
}).option("watch", {
|
|
16
70
|
alias: "w",
|
|
17
71
|
default: false,
|
|
@@ -25,21 +79,48 @@ await _yargs2.default.call(void 0, _helpers.hideBin.call(void 0, process.argv)).
|
|
|
25
79
|
});
|
|
26
80
|
},
|
|
27
81
|
async (argv) => {
|
|
82
|
+
let configDir;
|
|
28
83
|
try {
|
|
29
|
-
|
|
84
|
+
if (argv.args !== void 0 && !argv.tool) {
|
|
85
|
+
console.error("[FastMCP Error] --args requires --tool");
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (argv.tool && argv.watch) {
|
|
90
|
+
console.warn(
|
|
91
|
+
"[FastMCP] --watch is ignored when calling a tool with --tool: the server runs for a single call."
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
let configPath;
|
|
95
|
+
if (argv.tool) {
|
|
96
|
+
configDir = await _promises.mkdtemp.call(void 0, _path.join.call(void 0, _os.tmpdir.call(void 0, ), "fastmcp-dev-"));
|
|
97
|
+
configPath = _path.join.call(void 0, configDir, "mcp-cli.json");
|
|
98
|
+
await _promises.writeFile.call(void 0, configPath, buildDevConfig(argv.file), "utf8");
|
|
99
|
+
}
|
|
100
|
+
const [command, ...commandArgs] = buildDevCommand({
|
|
101
|
+
configPath,
|
|
102
|
+
file: argv.file,
|
|
103
|
+
tool: argv.tool,
|
|
104
|
+
toolArgs: argv.args,
|
|
105
|
+
watch: argv.watch
|
|
106
|
+
});
|
|
30
107
|
if (argv.verbose) {
|
|
31
|
-
console.log(
|
|
108
|
+
console.log(
|
|
109
|
+
`[FastMCP] Starting server: ${[command, ...commandArgs].join(" ")}`
|
|
110
|
+
);
|
|
32
111
|
console.log(`[FastMCP] File: ${argv.file}`);
|
|
33
112
|
console.log(
|
|
34
113
|
`[FastMCP] Watch mode: ${argv.watch ? "enabled" : "disabled"}`
|
|
35
114
|
);
|
|
115
|
+
if (argv.tool) {
|
|
116
|
+
console.log(`[FastMCP] Tool: ${argv.tool}`);
|
|
117
|
+
}
|
|
36
118
|
}
|
|
37
|
-
await _execa.execa.call(void 0, {
|
|
38
|
-
shell: true,
|
|
119
|
+
await _execa.execa.call(void 0, command, commandArgs, {
|
|
39
120
|
stderr: "inherit",
|
|
40
121
|
stdin: "inherit",
|
|
41
122
|
stdout: "inherit"
|
|
42
|
-
})
|
|
123
|
+
});
|
|
43
124
|
} catch (error) {
|
|
44
125
|
console.error(
|
|
45
126
|
"[FastMCP Error] Failed to start development server:",
|
|
@@ -48,7 +129,11 @@ await _yargs2.default.call(void 0, _helpers.hideBin.call(void 0, process.argv)).
|
|
|
48
129
|
if (argv.verbose && error instanceof Error && error.stack) {
|
|
49
130
|
console.error("[FastMCP Debug] Stack trace:", error.stack);
|
|
50
131
|
}
|
|
51
|
-
process.
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
} finally {
|
|
134
|
+
if (configDir) {
|
|
135
|
+
await _promises.rm.call(void 0, configDir, { force: true, recursive: true });
|
|
136
|
+
}
|
|
52
137
|
}
|
|
53
138
|
}
|
|
54
139
|
).command(
|
package/dist/bin/fastmcp.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/fastmcp/fastmcp/dist/bin/fastmcp.cjs","../../src/bin/fastmcp.ts"],"names":["yargs"],"mappings":"AAAA;AACA;AACA;ACAA,8BAAsB;AACtB,4EAAkB;AAClB,wCAAwB;AAExB,MAAM,6BAAA,8BAAM,OAAQ,CAAQ,IAAI,CAAC,CAAA,CAC9B,UAAA,CAAW,SAAS,CAAA,CACpB,OAAA;AAAA,EACC,YAAA;AAAA,EACA,4BAAA;AAAA,EACA,CAACA,MAAAA,EAAAA,GAAU;AACT,IAAA,OAAOA,MAAAA,CACJ,UAAA,CAAW,MAAA,EAAQ;AAAA,MAClB,YAAA,EAAc,IAAA;AAAA,MACd,QAAA,EAAU,6BAAA;AAAA,MACV,IAAA,EAAM;AAAA,IACR,CAAC,CAAA,CAEA,MAAA,CAAO,OAAA,EAAS;AAAA,MACf,KAAA,EAAO,GAAA;AAAA,MACP,OAAA,EAAS,KAAA;AAAA,MACT,QAAA,EAAU,2CAAA;AAAA,MACV,IAAA,EAAM;AAAA,IACR,CAAC,CAAA,CAEA,MAAA,CAAO,SAAA,EAAW;AAAA,MACjB,KAAA,EAAO,GAAA;AAAA,MACP,OAAA,EAAS,KAAA;AAAA,MACT,QAAA,EAAU,wBAAA;AAAA,MACV,IAAA,EAAM;AAAA,IACR,CAAC,CAAA;AAAA,EACL,CAAA;AAAA,EAEA,MAAA,CAAO,IAAA,EAAA,GAAS;AACd,IAAA,IAAI;AACF,MAAA,MAAM,QAAA,EAAU,IAAA,CAAK,MAAA,EACjB,CAAA,mCAAA,EAAsC,IAAA,CAAK,IAAI,CAAA,EAAA;AAGjC,MAAA;AACmC,QAAA;AACT,QAAA;AAClC,QAAA;AACsD,UAAA;AAC9D,QAAA;AACF,MAAA;AAEY,MAAA;AACH,QAAA;AACC,QAAA;AACD,QAAA;AACC,QAAA;AACE,MAAA;AACE,IAAA;AACN,MAAA;AACN,QAAA;AACqD,QAAA;AACvD,MAAA;AAE2D,MAAA;AACA,QAAA;AAC3D,MAAA;AAEc,MAAA;AAChB,IAAA;AACF,EAAA;AAGD;AACC,EAAA;AACA,EAAA;AACW,EAAA;AACuB,IAAA;AAChB,MAAA;AACJ,MAAA;AACJ,MAAA;AACP,IAAA;AACH,EAAA;AAEgB,EAAA;AACV,IAAA;AACU,MAAA;AACF,QAAA;AACA,QAAA;AACgD,MAAA;AAC5C,IAAA;AACN,MAAA;AACN,QAAA;AACqD,QAAA;AACvD,MAAA;AAEc,MAAA;AAChB,IAAA;AACF,EAAA;AAGD;AACC,EAAA;AACA,EAAA;AACW,EAAA;AAEa,IAAA;AACJ,MAAA;AACJ,MAAA;AACJ,MAAA;AAGU,IAAA;AACT,MAAA;AACE,MAAA;AACC,MAAA;AACJ,MAAA;AACP,IAAA;AACL,EAAA;AAEgB,EAAA;AACV,IAAA;AACsC,MAAA;AACD,MAAA;AACL,MAAA;AAEP,MAAA;AACkC,QAAA;AAC7C,QAAA;AAChB,MAAA;AAE2D,MAAA;AAIvD,MAAA;AAEA,MAAA;AACU,QAAA;AACH,UAAA;AACC,UAAA;AACA,UAAA;AACE,QAAA;AAE+C,QAAA;AAC3C,MAAA;AACyC,QAAA;AAEJ,QAAA;AACvB,UAAA;AAC9B,QAAA;AAEc,QAAA;AAChB,MAAA;AAEI,MAAA;AACU,QAAA;AACH,UAAA;AACC,UAAA;AACA,UAAA;AACT,QAAA;AAAA;AAAA;AAAA;AAIoC,qCAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAAA;AAQ/B,MAAA;AACwD,QAAA;AACM,QAAA;AAEtD,QAAA;AAChB,MAAA;AAEQ,MAAA;AACN,QAAA;AACF,MAAA;AACc,IAAA;AACN,MAAA;AACN,QAAA;AACqD,QAAA;AACvD,MAAA;AAEc,MAAA;AAChB,IAAA;AACF,EAAA;AAIU","file":"/home/runner/work/fastmcp/fastmcp/dist/bin/fastmcp.cjs","sourcesContent":[null,"#!/usr/bin/env node\n\nimport { execa } from \"execa\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\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(\"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 try {\n const command = argv.watch\n ? `npx @wong2/mcp-cli npx tsx --watch ${argv.file}`\n : `npx @wong2/mcp-cli npx tsx ${argv.file}`;\n\n if (argv.verbose) {\n console.log(`[FastMCP] Starting server: ${command}`);\n console.log(`[FastMCP] File: ${argv.file}`);\n console.log(\n `[FastMCP] Watch mode: ${argv.watch ? \"enabled\" : \"disabled\"}`,\n );\n }\n\n await execa({\n shell: true,\n stderr: \"inherit\",\n stdin: \"inherit\",\n stdout: \"inherit\",\n })`${command}`;\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 process.exit(1);\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"]}
|
|
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"]}
|
package/dist/bin/fastmcp.js
CHANGED
|
@@ -2,8 +2,55 @@
|
|
|
2
2
|
|
|
3
3
|
// src/bin/fastmcp.ts
|
|
4
4
|
import { execa } from "execa";
|
|
5
|
+
import { mkdtemp, rm, writeFile } from "fs/promises";
|
|
6
|
+
import { tmpdir } from "os";
|
|
7
|
+
import { join } from "path";
|
|
5
8
|
import yargs from "yargs";
|
|
6
9
|
import { hideBin } from "yargs/helpers";
|
|
10
|
+
|
|
11
|
+
// src/bin/devCommand.ts
|
|
12
|
+
var DEV_SERVER_NAME = "dev";
|
|
13
|
+
var buildDevConfig = (file) => JSON.stringify(
|
|
14
|
+
{
|
|
15
|
+
mcpServers: {
|
|
16
|
+
[DEV_SERVER_NAME]: {
|
|
17
|
+
args: ["tsx", file],
|
|
18
|
+
command: "npx"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
null,
|
|
23
|
+
2
|
|
24
|
+
);
|
|
25
|
+
var buildDevCommand = (options) => {
|
|
26
|
+
const { configPath, file, tool, toolArgs, watch = false } = options;
|
|
27
|
+
if (tool) {
|
|
28
|
+
if (!configPath) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
"configPath is required when calling a tool non-interactively"
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
return [
|
|
34
|
+
"npx",
|
|
35
|
+
"@wong2/mcp-cli",
|
|
36
|
+
"-c",
|
|
37
|
+
configPath,
|
|
38
|
+
"call-tool",
|
|
39
|
+
`${DEV_SERVER_NAME}:${tool}`,
|
|
40
|
+
...toolArgs === void 0 ? [] : ["--args", toolArgs]
|
|
41
|
+
];
|
|
42
|
+
}
|
|
43
|
+
return [
|
|
44
|
+
"npx",
|
|
45
|
+
"@wong2/mcp-cli",
|
|
46
|
+
"npx",
|
|
47
|
+
"tsx",
|
|
48
|
+
...watch ? ["--watch"] : [],
|
|
49
|
+
file
|
|
50
|
+
];
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// src/bin/fastmcp.ts
|
|
7
54
|
await yargs(hideBin(process.argv)).scriptName("fastmcp").command(
|
|
8
55
|
"dev <file>",
|
|
9
56
|
"Start a development server",
|
|
@@ -12,6 +59,13 @@ await yargs(hideBin(process.argv)).scriptName("fastmcp").command(
|
|
|
12
59
|
demandOption: true,
|
|
13
60
|
describe: "The path to the server file",
|
|
14
61
|
type: "string"
|
|
62
|
+
}).option("args", {
|
|
63
|
+
describe: `JSON arguments passed to the tool (requires --tool), e.g. '{"a":1}'`,
|
|
64
|
+
type: "string"
|
|
65
|
+
}).option("tool", {
|
|
66
|
+
alias: "t",
|
|
67
|
+
describe: "Call a tool non-interactively instead of launching the inspector",
|
|
68
|
+
type: "string"
|
|
15
69
|
}).option("watch", {
|
|
16
70
|
alias: "w",
|
|
17
71
|
default: false,
|
|
@@ -25,21 +79,48 @@ await yargs(hideBin(process.argv)).scriptName("fastmcp").command(
|
|
|
25
79
|
});
|
|
26
80
|
},
|
|
27
81
|
async (argv) => {
|
|
82
|
+
let configDir;
|
|
28
83
|
try {
|
|
29
|
-
|
|
84
|
+
if (argv.args !== void 0 && !argv.tool) {
|
|
85
|
+
console.error("[FastMCP Error] --args requires --tool");
|
|
86
|
+
process.exitCode = 1;
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (argv.tool && argv.watch) {
|
|
90
|
+
console.warn(
|
|
91
|
+
"[FastMCP] --watch is ignored when calling a tool with --tool: the server runs for a single call."
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
let configPath;
|
|
95
|
+
if (argv.tool) {
|
|
96
|
+
configDir = await mkdtemp(join(tmpdir(), "fastmcp-dev-"));
|
|
97
|
+
configPath = join(configDir, "mcp-cli.json");
|
|
98
|
+
await writeFile(configPath, buildDevConfig(argv.file), "utf8");
|
|
99
|
+
}
|
|
100
|
+
const [command, ...commandArgs] = buildDevCommand({
|
|
101
|
+
configPath,
|
|
102
|
+
file: argv.file,
|
|
103
|
+
tool: argv.tool,
|
|
104
|
+
toolArgs: argv.args,
|
|
105
|
+
watch: argv.watch
|
|
106
|
+
});
|
|
30
107
|
if (argv.verbose) {
|
|
31
|
-
console.log(
|
|
108
|
+
console.log(
|
|
109
|
+
`[FastMCP] Starting server: ${[command, ...commandArgs].join(" ")}`
|
|
110
|
+
);
|
|
32
111
|
console.log(`[FastMCP] File: ${argv.file}`);
|
|
33
112
|
console.log(
|
|
34
113
|
`[FastMCP] Watch mode: ${argv.watch ? "enabled" : "disabled"}`
|
|
35
114
|
);
|
|
115
|
+
if (argv.tool) {
|
|
116
|
+
console.log(`[FastMCP] Tool: ${argv.tool}`);
|
|
117
|
+
}
|
|
36
118
|
}
|
|
37
|
-
await execa({
|
|
38
|
-
shell: true,
|
|
119
|
+
await execa(command, commandArgs, {
|
|
39
120
|
stderr: "inherit",
|
|
40
121
|
stdin: "inherit",
|
|
41
122
|
stdout: "inherit"
|
|
42
|
-
})
|
|
123
|
+
});
|
|
43
124
|
} catch (error) {
|
|
44
125
|
console.error(
|
|
45
126
|
"[FastMCP Error] Failed to start development server:",
|
|
@@ -48,7 +129,11 @@ await yargs(hideBin(process.argv)).scriptName("fastmcp").command(
|
|
|
48
129
|
if (argv.verbose && error instanceof Error && error.stack) {
|
|
49
130
|
console.error("[FastMCP Debug] Stack trace:", error.stack);
|
|
50
131
|
}
|
|
51
|
-
process.
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
} finally {
|
|
134
|
+
if (configDir) {
|
|
135
|
+
await rm(configDir, { force: true, recursive: true });
|
|
136
|
+
}
|
|
52
137
|
}
|
|
53
138
|
}
|
|
54
139
|
).command(
|
package/dist/bin/fastmcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bin/fastmcp.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { execa } from \"execa\";\nimport yargs from \"yargs\";\nimport { hideBin } from \"yargs/helpers\";\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(\"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 try {\n const command = argv.watch\n ? `npx @wong2/mcp-cli npx tsx --watch ${argv.file}`\n : `npx @wong2/mcp-cli npx tsx ${argv.file}`;\n\n if (argv.verbose) {\n console.log(`[FastMCP] Starting server: ${command}`);\n console.log(`[FastMCP] File: ${argv.file}`);\n console.log(\n `[FastMCP] Watch mode: ${argv.watch ? \"enabled\" : \"disabled\"}`,\n );\n }\n\n await execa({\n shell: true,\n stderr: \"inherit\",\n stdin: \"inherit\",\n stdout: \"inherit\",\n })`${command}`;\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 process.exit(1);\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"],"mappings":"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","names":["yargs"]}
|
|
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":"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","names":["yargs"]}
|
|
@@ -1691,6 +1691,17 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1691
1691
|
version: this.#options.version
|
|
1692
1692
|
});
|
|
1693
1693
|
await session.connect(transport);
|
|
1694
|
+
let stdinClosed = false;
|
|
1695
|
+
const onStdinClose = () => {
|
|
1696
|
+
if (stdinClosed) return;
|
|
1697
|
+
stdinClosed = true;
|
|
1698
|
+
process.stdin.off("close", onStdinClose);
|
|
1699
|
+
process.stdin.off("end", onStdinClose);
|
|
1700
|
+
transport.close().catch(() => {
|
|
1701
|
+
});
|
|
1702
|
+
};
|
|
1703
|
+
process.stdin.on("close", onStdinClose);
|
|
1704
|
+
process.stdin.on("end", onStdinClose);
|
|
1694
1705
|
this.#sessions.push(session);
|
|
1695
1706
|
session.once("error", () => {
|
|
1696
1707
|
this.#removeSession(session);
|
|
@@ -1698,6 +1709,8 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1698
1709
|
if (transport.onclose) {
|
|
1699
1710
|
const originalOnClose = transport.onclose;
|
|
1700
1711
|
transport.onclose = () => {
|
|
1712
|
+
process.stdin.off("close", onStdinClose);
|
|
1713
|
+
process.stdin.off("end", onStdinClose);
|
|
1701
1714
|
this.#removeSession(session);
|
|
1702
1715
|
if (originalOnClose) {
|
|
1703
1716
|
originalOnClose();
|
|
@@ -1705,6 +1718,8 @@ var FastMCP = class extends FastMCPEventEmitter {
|
|
|
1705
1718
|
};
|
|
1706
1719
|
} else {
|
|
1707
1720
|
transport.onclose = () => {
|
|
1721
|
+
process.stdin.off("close", onStdinClose);
|
|
1722
|
+
process.stdin.off("end", onStdinClose);
|
|
1708
1723
|
this.#removeSession(session);
|
|
1709
1724
|
};
|
|
1710
1725
|
}
|
|
@@ -2351,4 +2366,4 @@ export {
|
|
|
2351
2366
|
FastMCPSession,
|
|
2352
2367
|
FastMCP
|
|
2353
2368
|
};
|
|
2354
|
-
//# sourceMappingURL=chunk-
|
|
2369
|
+
//# sourceMappingURL=chunk-2PFUZL7I.js.map
|