@agiflowai/one-mcp 0.2.6 → 0.3.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 CHANGED
@@ -128,6 +128,12 @@ mcpServers:
128
128
  command: node
129
129
  args: ["server.js"]
130
130
  disabled: true
131
+
132
+ # Custom timeout for slow servers
133
+ slow-server:
134
+ command: npx
135
+ args: ["-y", "@heavy/mcp-package"]
136
+ timeout: 60000 # 60 seconds (default: 30000)
131
137
  ```
132
138
 
133
139
  ### Environment Variables
@@ -259,9 +265,51 @@ When multiple paths are configured, skills from earlier paths take precedence ov
259
265
 
260
266
  You can also convert MCP server prompts into skills. This allows you to expose prompts from MCP servers as executable skills that AI agents can invoke.
261
267
 
262
- #### Configuration
268
+ #### Auto-Detection from Front-Matter (Recommended)
269
+
270
+ The easiest way to create prompt-based skills is to add YAML front-matter directly in your prompt content. one-mcp automatically detects prompts with `name` and `description` front-matter and exposes them as skills.
271
+
272
+ **Prompt content with front-matter:**
273
+ ```markdown
274
+ ---
275
+ name: code-reviewer
276
+ description: Review code for best practices and potential issues
277
+ ---
278
+
279
+ # Code Review Instructions
280
+
281
+ When reviewing code, follow these guidelines...
282
+ ```
263
283
 
264
- Add a `prompts` section under a server's `config`:
284
+ MCP servers like `@agiflowai/scaffold-mcp` support the `--prompt-as-skill` flag to automatically add front-matter to prompts:
285
+
286
+ ```yaml
287
+ mcpServers:
288
+ scaffold-mcp:
289
+ command: npx
290
+ args:
291
+ - -y
292
+ - "@agiflowai/scaffold-mcp"
293
+ - "mcp-serve"
294
+ - "--prompt-as-skill" # Enables front-matter in prompts
295
+ ```
296
+
297
+ **Multi-line descriptions** are supported using YAML block scalars:
298
+
299
+ ```markdown
300
+ ---
301
+ name: complex-skill
302
+ description: |
303
+ A skill that does multiple things:
304
+ - First capability
305
+ - Second capability
306
+ - Third capability
307
+ ---
308
+ ```
309
+
310
+ #### Explicit Configuration (Alternative)
311
+
312
+ You can also explicitly configure which prompts should be exposed as skills:
265
313
 
266
314
  ```yaml
267
315
  mcpServers:
@@ -286,14 +334,14 @@ mcpServers:
286
334
 
287
335
  #### How Prompt-Based Skills Work
288
336
 
289
- 1. **Configuration**: Define which prompts should be exposed as skills in the server config
290
- 2. **Discovery**: Prompt-based skills appear alongside file-based skills in `describe_tools`
337
+ 1. **Discovery**: one-mcp scans all prompts from connected servers for front-matter with `name` and `description`
338
+ 2. **Fallback**: Explicitly configured prompts (in `config.prompts`) take precedence over auto-detected ones
291
339
  3. **Invocation**: When an AI agent requests a prompt-based skill, one-mcp:
292
340
  - Fetches the prompt content from the MCP server
293
341
  - Returns the prompt messages as skill instructions
294
342
  4. **Execution**: The AI agent follows the skill instructions
295
343
 
296
- #### Skill Configuration Fields
344
+ #### Skill Configuration Fields (Explicit Config)
297
345
 
298
346
  | Field | Required | Description |
299
347
  |-------|----------|-------------|
@@ -301,6 +349,12 @@ mcpServers:
301
349
  | `description` | Yes | Brief description of what the skill does |
302
350
  | `folder` | No | Optional folder path for skill resources |
303
351
 
352
+ #### Skill Naming and Precedence
353
+
354
+ - **File-based skills** take precedence over prompt-based skills with the same name
355
+ - Skills are only prefixed with `skill__` when they clash with MCP tool names
356
+ - Skills that only clash with other skills are deduplicated (first one wins, no prefix)
357
+
304
358
  #### Example Use Case
305
359
 
306
360
  Convert a complex prompt from an MCP server into a reusable skill:
@@ -366,6 +420,9 @@ npx @agiflowai/one-mcp mcp-serve --config ./mcp-config.yaml --type http --port 3
366
420
  # Initialize config file
367
421
  npx @agiflowai/one-mcp init --output mcp-config.yaml
368
422
 
423
+ # Pre-download packages for faster startup
424
+ npx @agiflowai/one-mcp prefetch --config ./mcp-config.yaml
425
+
369
426
  # List all tools from configured servers
370
427
  npx @agiflowai/one-mcp list-tools --config ./mcp-config.yaml
371
428
 
@@ -376,6 +433,31 @@ npx @agiflowai/one-mcp describe-tools --config ./mcp-config.yaml --tools read_fi
376
433
  npx @agiflowai/one-mcp use-tool --config ./mcp-config.yaml --tool-name read_file --args '{"path": "/tmp/test.txt"}'
377
434
  ```
378
435
 
436
+ ### Prefetch Command
437
+
438
+ Pre-download packages used by MCP servers (npx, pnpx, uvx, uv) to speed up initial connections:
439
+
440
+ ```bash
441
+ # Prefetch all packages
442
+ npx @agiflowai/one-mcp prefetch --config ./mcp-config.yaml
443
+
444
+ # Dry run - see what would be prefetched
445
+ npx @agiflowai/one-mcp prefetch --config ./mcp-config.yaml --dry-run
446
+
447
+ # Run prefetch in parallel (faster)
448
+ npx @agiflowai/one-mcp prefetch --config ./mcp-config.yaml --parallel
449
+
450
+ # Filter by package manager
451
+ npx @agiflowai/one-mcp prefetch --config ./mcp-config.yaml --filter npx
452
+ ```
453
+
454
+ | Option | Description |
455
+ |--------|-------------|
456
+ | `-c, --config` | Path to config file |
457
+ | `-p, --parallel` | Run prefetch commands in parallel |
458
+ | `-d, --dry-run` | Show what would be prefetched without executing |
459
+ | `-f, --filter` | Filter by package manager: `npx`, `pnpx`, `uvx`, or `uv` |
460
+
379
461
  ### Server Options
380
462
 
381
463
  | Option | Description | Default |
package/dist/cli.cjs CHANGED
@@ -1,10 +1,11 @@
1
1
  #!/usr/bin/env node
2
- const require_http = require('./http-xSfxBa8A.cjs');
2
+ const require_http = require('./http-BYBRKvD4.cjs');
3
3
  let node_fs_promises = require("node:fs/promises");
4
4
  let node_path = require("node:path");
5
5
  let liquidjs = require("liquidjs");
6
6
  let commander = require("commander");
7
7
  let __agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
8
+ let node_child_process = require("node:child_process");
8
9
 
9
10
  //#region src/types/index.ts
10
11
  /**
@@ -546,9 +547,462 @@ const initCommand = new commander.Command("init").description("Initialize MCP co
546
547
  }
547
548
  });
548
549
 
550
+ //#endregion
551
+ //#region src/services/PrefetchService/constants.ts
552
+ /**
553
+ * PrefetchService Constants
554
+ *
555
+ * Constants for package manager commands and process configuration.
556
+ */
557
+ /** Transport type for stdio-based MCP servers */
558
+ const TRANSPORT_STDIO = "stdio";
559
+ /** npx command name */
560
+ const COMMAND_NPX = "npx";
561
+ /** npm command name */
562
+ const COMMAND_NPM = "npm";
563
+ /** pnpx command name (pnpm's npx equivalent) */
564
+ const COMMAND_PNPX = "pnpx";
565
+ /** pnpm command name */
566
+ const COMMAND_PNPM = "pnpm";
567
+ /** uvx command name */
568
+ const COMMAND_UVX = "uvx";
569
+ /** uv command name */
570
+ const COMMAND_UV = "uv";
571
+ /** Path suffix for npx command */
572
+ const COMMAND_NPX_SUFFIX = "/npx";
573
+ /** Path suffix for pnpx command */
574
+ const COMMAND_PNPX_SUFFIX = "/pnpx";
575
+ /** Path suffix for uvx command */
576
+ const COMMAND_UVX_SUFFIX = "/uvx";
577
+ /** Path suffix for uv command */
578
+ const COMMAND_UV_SUFFIX = "/uv";
579
+ /** Run subcommand for uv */
580
+ const ARG_RUN = "run";
581
+ /** Tool subcommand for uv */
582
+ const ARG_TOOL = "tool";
583
+ /** Install subcommand for uv tool and npm/pnpm */
584
+ const ARG_INSTALL = "install";
585
+ /** Add subcommand for pnpm */
586
+ const ARG_ADD = "add";
587
+ /** Global flag for npm/pnpm install */
588
+ const ARG_GLOBAL = "-g";
589
+ /** Flag prefix for command arguments */
590
+ const FLAG_PREFIX = "-";
591
+ /** npx --package flag (long form) */
592
+ const FLAG_PACKAGE_LONG = "--package";
593
+ /** npx -p flag (short form) */
594
+ const FLAG_PACKAGE_SHORT = "-p";
595
+ /** Equals delimiter used in flag=value patterns */
596
+ const EQUALS_DELIMITER = "=";
597
+ /**
598
+ * Regex pattern for valid package names (npm, pnpm, uvx, uv)
599
+ * Allows: @scope/package-name@version, package-name, package_name
600
+ * Prevents shell metacharacters that could enable command injection
601
+ * @example
602
+ * // Valid: '@scope/package@1.0.0', 'my-package', 'my_package', '@org/pkg'
603
+ * // Invalid: 'pkg; rm -rf /', 'pkg$(cmd)', 'pkg`whoami`', 'pkg|cat /etc/passwd'
604
+ */
605
+ const VALID_PACKAGE_NAME_PATTERN = /^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/;
606
+ /** Windows platform identifier */
607
+ const PLATFORM_WIN32 = "win32";
608
+ /** Success exit code */
609
+ const EXIT_CODE_SUCCESS = 0;
610
+ /** Stdio option to ignore stream */
611
+ const STDIO_IGNORE = "ignore";
612
+ /** Stdio option to pipe stream */
613
+ const STDIO_PIPE = "pipe";
614
+
615
+ //#endregion
616
+ //#region src/services/PrefetchService/PrefetchService.ts
617
+ /**
618
+ * PrefetchService
619
+ *
620
+ * DESIGN PATTERNS:
621
+ * - Service pattern for business logic encapsulation
622
+ * - Single responsibility principle
623
+ *
624
+ * CODING STANDARDS:
625
+ * - Use async/await for asynchronous operations
626
+ * - Throw descriptive errors for error cases
627
+ * - Keep methods focused and well-named
628
+ * - Document complex logic with comments
629
+ *
630
+ * AVOID:
631
+ * - Mixing concerns (keep focused on single domain)
632
+ * - Direct tool implementation (services should be tool-agnostic)
633
+ */
634
+ /**
635
+ * Type guard to check if a config object is an McpStdioConfig
636
+ * @param config - Config object to check
637
+ * @returns True if config has required McpStdioConfig properties
638
+ */
639
+ function isMcpStdioConfig(config) {
640
+ return typeof config === "object" && config !== null && "command" in config;
641
+ }
642
+ /**
643
+ * PrefetchService handles pre-downloading packages used by MCP servers.
644
+ * Supports npx (Node.js), uvx (Python/uv), and uv run commands.
645
+ *
646
+ * @example
647
+ * ```typescript
648
+ * const service = new PrefetchService({
649
+ * mcpConfig: await configFetcher.fetchConfiguration(),
650
+ * parallel: true,
651
+ * });
652
+ * const packages = service.extractPackages();
653
+ * const summary = await service.prefetch();
654
+ * ```
655
+ */
656
+ var PrefetchService = class {
657
+ config;
658
+ /**
659
+ * Creates a new PrefetchService instance
660
+ * @param config - Service configuration options
661
+ */
662
+ constructor(config) {
663
+ this.config = config;
664
+ }
665
+ /**
666
+ * Extract all prefetchable packages from the MCP configuration
667
+ * @returns Array of package info objects
668
+ */
669
+ extractPackages() {
670
+ const packages = [];
671
+ const { mcpConfig, filter } = this.config;
672
+ for (const [serverName, serverConfig] of Object.entries(mcpConfig.mcpServers)) {
673
+ if (serverConfig.disabled) continue;
674
+ if (serverConfig.transport !== TRANSPORT_STDIO) continue;
675
+ if (!isMcpStdioConfig(serverConfig.config)) continue;
676
+ const packageInfo = this.extractPackageInfo(serverName, serverConfig.config);
677
+ if (packageInfo) {
678
+ if (filter && packageInfo.packageManager !== filter) continue;
679
+ packages.push(packageInfo);
680
+ }
681
+ }
682
+ return packages;
683
+ }
684
+ /**
685
+ * Prefetch all packages from the configuration
686
+ * @returns Summary of prefetch results
687
+ * @throws Error if prefetch operation fails unexpectedly
688
+ */
689
+ async prefetch() {
690
+ try {
691
+ const packages = this.extractPackages();
692
+ const results = [];
693
+ if (packages.length === 0) return {
694
+ totalPackages: 0,
695
+ successful: 0,
696
+ failed: 0,
697
+ results: []
698
+ };
699
+ if (this.config.parallel) {
700
+ const promises = packages.map(async (pkg) => this.prefetchPackage(pkg));
701
+ results.push(...await Promise.all(promises));
702
+ } else for (const pkg of packages) {
703
+ const result = await this.prefetchPackage(pkg);
704
+ results.push(result);
705
+ }
706
+ const successful = results.filter((r) => r.success).length;
707
+ const failed = results.filter((r) => !r.success).length;
708
+ return {
709
+ totalPackages: packages.length,
710
+ successful,
711
+ failed,
712
+ results
713
+ };
714
+ } catch (error) {
715
+ throw new Error(`Failed to prefetch packages: ${error instanceof Error ? error.message : String(error)}`);
716
+ }
717
+ }
718
+ /**
719
+ * Prefetch a single package
720
+ * @param pkg - Package info to prefetch
721
+ * @returns Result of the prefetch operation
722
+ */
723
+ async prefetchPackage(pkg) {
724
+ try {
725
+ const [command, ...args] = pkg.fullCommand;
726
+ const result = await this.runCommand(command, args);
727
+ return {
728
+ package: pkg,
729
+ success: result.success,
730
+ output: result.output
731
+ };
732
+ } catch (error) {
733
+ return {
734
+ package: pkg,
735
+ success: false,
736
+ output: error instanceof Error ? error.message : String(error)
737
+ };
738
+ }
739
+ }
740
+ /**
741
+ * Validate package name to prevent command injection
742
+ * @param packageName - Package name to validate
743
+ * @returns True if package name is safe, false otherwise
744
+ * @remarks Rejects package names containing shell metacharacters
745
+ * @example
746
+ * isValidPackageName('@scope/package') // true
747
+ * isValidPackageName('my-package@1.0.0') // true
748
+ * isValidPackageName('pkg; rm -rf /') // false (shell injection)
749
+ * isValidPackageName('pkg$(whoami)') // false (command substitution)
750
+ */
751
+ isValidPackageName(packageName) {
752
+ return VALID_PACKAGE_NAME_PATTERN.test(packageName);
753
+ }
754
+ /**
755
+ * Extract package info from a server's stdio config
756
+ * @param serverName - Name of the MCP server
757
+ * @param config - Stdio configuration for the server
758
+ * @returns Package info if extractable, null otherwise
759
+ */
760
+ extractPackageInfo(serverName, config) {
761
+ const command = config.command.toLowerCase();
762
+ const args = config.args || [];
763
+ if (command === COMMAND_NPX || command.endsWith(COMMAND_NPX_SUFFIX)) {
764
+ const packageName = this.extractNpxPackage(args);
765
+ if (packageName && this.isValidPackageName(packageName)) return {
766
+ serverName,
767
+ packageManager: COMMAND_NPX,
768
+ packageName,
769
+ fullCommand: [
770
+ COMMAND_NPM,
771
+ ARG_INSTALL,
772
+ ARG_GLOBAL,
773
+ packageName
774
+ ]
775
+ };
776
+ }
777
+ if (command === COMMAND_PNPX || command.endsWith(COMMAND_PNPX_SUFFIX)) {
778
+ const packageName = this.extractNpxPackage(args);
779
+ if (packageName && this.isValidPackageName(packageName)) return {
780
+ serverName,
781
+ packageManager: COMMAND_PNPX,
782
+ packageName,
783
+ fullCommand: [
784
+ COMMAND_PNPM,
785
+ ARG_ADD,
786
+ ARG_GLOBAL,
787
+ packageName
788
+ ]
789
+ };
790
+ }
791
+ if (command === COMMAND_UVX || command.endsWith(COMMAND_UVX_SUFFIX)) {
792
+ const packageName = this.extractUvxPackage(args);
793
+ if (packageName && this.isValidPackageName(packageName)) return {
794
+ serverName,
795
+ packageManager: COMMAND_UVX,
796
+ packageName,
797
+ fullCommand: [COMMAND_UVX, packageName]
798
+ };
799
+ }
800
+ if ((command === COMMAND_UV || command.endsWith(COMMAND_UV_SUFFIX)) && args.includes(ARG_RUN)) {
801
+ const packageName = this.extractUvRunPackage(args);
802
+ if (packageName && this.isValidPackageName(packageName)) return {
803
+ serverName,
804
+ packageManager: COMMAND_UV,
805
+ packageName,
806
+ fullCommand: [
807
+ COMMAND_UV,
808
+ ARG_TOOL,
809
+ ARG_INSTALL,
810
+ packageName
811
+ ]
812
+ };
813
+ }
814
+ return null;
815
+ }
816
+ /**
817
+ * Extract package name from npx command args
818
+ * @param args - Command arguments
819
+ * @returns Package name or null
820
+ * @remarks Handles --package=value, --package value, -p value patterns.
821
+ * Falls back to first non-flag argument if no --package/-p flag found.
822
+ * Returns null if flag has no value or is followed by another flag.
823
+ * When multiple --package flags exist, returns the first valid one.
824
+ * @example
825
+ * extractNpxPackage(['--package=@scope/pkg']) // returns '@scope/pkg'
826
+ * extractNpxPackage(['--package', 'pkg-name']) // returns 'pkg-name'
827
+ * extractNpxPackage(['-p', 'pkg']) // returns 'pkg'
828
+ * extractNpxPackage(['-y', 'pkg-name', '--flag']) // returns 'pkg-name' (fallback)
829
+ * extractNpxPackage(['--package=']) // returns null (empty value)
830
+ */
831
+ extractNpxPackage(args) {
832
+ for (let i = 0; i < args.length; i++) {
833
+ const arg = args[i];
834
+ if (arg.startsWith(FLAG_PACKAGE_LONG + EQUALS_DELIMITER)) return arg.slice(FLAG_PACKAGE_LONG.length + EQUALS_DELIMITER.length) || null;
835
+ if (arg === FLAG_PACKAGE_LONG && i + 1 < args.length) {
836
+ const nextArg = args[i + 1];
837
+ if (!nextArg.startsWith(FLAG_PREFIX)) return nextArg;
838
+ }
839
+ if (arg === FLAG_PACKAGE_SHORT && i + 1 < args.length) {
840
+ const nextArg = args[i + 1];
841
+ if (!nextArg.startsWith(FLAG_PREFIX)) return nextArg;
842
+ }
843
+ }
844
+ for (const arg of args) {
845
+ if (arg.startsWith(FLAG_PREFIX)) continue;
846
+ return arg;
847
+ }
848
+ return null;
849
+ }
850
+ /**
851
+ * Extract package name from uvx command args
852
+ * @param args - Command arguments
853
+ * @returns Package name or null
854
+ * @remarks Assumes the first non-flag argument is the package name.
855
+ * Handles both single (-) and double (--) dash flags.
856
+ * @example
857
+ * extractUvxPackage(['mcp-server-fetch']) // returns 'mcp-server-fetch'
858
+ * extractUvxPackage(['--quiet', 'pkg-name']) // returns 'pkg-name'
859
+ */
860
+ extractUvxPackage(args) {
861
+ for (const arg of args) {
862
+ if (arg.startsWith(FLAG_PREFIX)) continue;
863
+ return arg;
864
+ }
865
+ return null;
866
+ }
867
+ /**
868
+ * Extract package name from uv run command args
869
+ * @param args - Command arguments
870
+ * @returns Package name or null
871
+ * @remarks Looks for the first non-flag argument after the 'run' subcommand.
872
+ * Returns null if 'run' is not found in args.
873
+ * @example
874
+ * extractUvRunPackage(['run', 'mcp-server']) // returns 'mcp-server'
875
+ * extractUvRunPackage(['run', '--verbose', 'pkg']) // returns 'pkg'
876
+ * extractUvRunPackage(['install', 'pkg']) // returns null (no 'run')
877
+ */
878
+ extractUvRunPackage(args) {
879
+ const runIndex = args.indexOf(ARG_RUN);
880
+ if (runIndex === -1) return null;
881
+ for (let i = runIndex + 1; i < args.length; i++) {
882
+ const arg = args[i];
883
+ if (arg.startsWith(FLAG_PREFIX)) continue;
884
+ return arg;
885
+ }
886
+ return null;
887
+ }
888
+ /**
889
+ * Run a shell command and capture output
890
+ * @param command - Command to run
891
+ * @param args - Command arguments
892
+ * @returns Promise with success status and output
893
+ */
894
+ runCommand(command, args) {
895
+ return new Promise((resolve$1) => {
896
+ const proc = (0, node_child_process.spawn)(command, args, {
897
+ stdio: [
898
+ STDIO_IGNORE,
899
+ STDIO_PIPE,
900
+ STDIO_PIPE
901
+ ],
902
+ shell: process.platform === PLATFORM_WIN32
903
+ });
904
+ let stdout = "";
905
+ let stderr = "";
906
+ proc.stdout?.on("data", (data) => {
907
+ stdout += data.toString();
908
+ });
909
+ proc.stderr?.on("data", (data) => {
910
+ stderr += data.toString();
911
+ });
912
+ proc.on("close", (code) => {
913
+ resolve$1({
914
+ success: code === EXIT_CODE_SUCCESS,
915
+ output: stdout || stderr
916
+ });
917
+ });
918
+ proc.on("error", (error) => {
919
+ resolve$1({
920
+ success: false,
921
+ output: error.message
922
+ });
923
+ });
924
+ });
925
+ }
926
+ };
927
+
928
+ //#endregion
929
+ //#region src/commands/prefetch.ts
930
+ /**
931
+ * Prefetch Command
932
+ *
933
+ * DESIGN PATTERNS:
934
+ * - Command pattern with Commander for CLI argument parsing
935
+ * - Async/await pattern for asynchronous operations
936
+ * - Error handling pattern with try-catch and proper exit codes
937
+ *
938
+ * CODING STANDARDS:
939
+ * - Use async action handlers for asynchronous operations
940
+ * - Provide clear option descriptions and default values
941
+ * - Handle errors gracefully with process.exit()
942
+ * - Log progress and errors to console
943
+ * - Use Commander's .option() and .argument() for inputs
944
+ *
945
+ * AVOID:
946
+ * - Synchronous blocking operations in action handlers
947
+ * - Missing error handling (always use try-catch)
948
+ * - Hardcoded values (use options or environment variables)
949
+ * - Not exiting with appropriate exit codes on errors
950
+ */
951
+ /**
952
+ * Pre-download packages used by MCP servers (npx, pnpx, uvx, uv)
953
+ */
954
+ const prefetchCommand = new commander.Command("prefetch").description("Pre-download packages used by MCP servers (npx, pnpx, uvx, uv)").option("-c, --config <path>", "Path to MCP server configuration file").option("-p, --parallel", "Run prefetch commands in parallel", false).option("-d, --dry-run", "Show what would be prefetched without executing", false).option("-f, --filter <type>", "Filter by package manager type: npx, pnpx, uvx, or uv").action(async (options) => {
955
+ try {
956
+ const configFilePath = options.config || require_http.findConfigFile();
957
+ if (!configFilePath) {
958
+ __agiflowai_aicode_utils.print.error("No MCP configuration file found.");
959
+ __agiflowai_aicode_utils.print.info("Use --config <path> to specify a config file, or run \"one-mcp init\" to create one.");
960
+ process.exit(1);
961
+ }
962
+ __agiflowai_aicode_utils.print.info(`Loading configuration from: ${configFilePath}`);
963
+ const prefetchService = new PrefetchService({
964
+ mcpConfig: await new require_http.ConfigFetcherService({
965
+ configFilePath,
966
+ useCache: false
967
+ }).fetchConfiguration(true),
968
+ filter: options.filter,
969
+ parallel: options.parallel
970
+ });
971
+ const packages = prefetchService.extractPackages();
972
+ if (packages.length === 0) {
973
+ __agiflowai_aicode_utils.print.warning("No packages found to prefetch.");
974
+ __agiflowai_aicode_utils.print.info("Prefetch supports: npx, pnpx, uvx, and uv run commands");
975
+ return;
976
+ }
977
+ __agiflowai_aicode_utils.print.info(`Found ${packages.length} package(s) to prefetch:`);
978
+ for (const pkg of packages) __agiflowai_aicode_utils.print.item(`${pkg.serverName}: ${pkg.packageManager} ${pkg.packageName}`);
979
+ if (options.dryRun) {
980
+ __agiflowai_aicode_utils.print.newline();
981
+ __agiflowai_aicode_utils.print.header("Dry run mode - commands that would be executed:");
982
+ for (const pkg of packages) __agiflowai_aicode_utils.print.indent(pkg.fullCommand.join(" "));
983
+ return;
984
+ }
985
+ __agiflowai_aicode_utils.print.newline();
986
+ __agiflowai_aicode_utils.print.info("Prefetching packages...");
987
+ const summary = await prefetchService.prefetch();
988
+ __agiflowai_aicode_utils.print.newline();
989
+ if (summary.failed === 0) __agiflowai_aicode_utils.print.success(`Prefetch complete: ${summary.successful} succeeded, ${summary.failed} failed`);
990
+ else __agiflowai_aicode_utils.print.warning(`Prefetch complete: ${summary.successful} succeeded, ${summary.failed} failed`);
991
+ if (summary.failed > 0) {
992
+ __agiflowai_aicode_utils.print.newline();
993
+ __agiflowai_aicode_utils.print.error("Failed packages:");
994
+ for (const result of summary.results.filter((r) => !r.success)) __agiflowai_aicode_utils.print.item(`${result.package.serverName} (${result.package.packageName}): ${result.output.trim()}`);
995
+ process.exit(1);
996
+ }
997
+ } catch (error) {
998
+ __agiflowai_aicode_utils.print.error("Error executing prefetch:", error instanceof Error ? error.message : String(error));
999
+ process.exit(1);
1000
+ }
1001
+ });
1002
+
549
1003
  //#endregion
550
1004
  //#region package.json
551
- var version = "0.2.5";
1005
+ var version = "0.2.2";
552
1006
 
553
1007
  //#endregion
554
1008
  //#region src/cli.ts
@@ -574,15 +1028,24 @@ var version = "0.2.5";
574
1028
  * Main entry point
575
1029
  */
576
1030
  async function main() {
577
- const program = new commander.Command();
578
- program.name("one-mcp").description("One MCP server package").version(version);
579
- program.addCommand(initCommand);
580
- program.addCommand(mcpServeCommand);
581
- program.addCommand(listToolsCommand);
582
- program.addCommand(describeToolsCommand);
583
- program.addCommand(useToolCommand);
584
- await program.parseAsync(process.argv);
1031
+ try {
1032
+ const program = new commander.Command();
1033
+ program.name("one-mcp").description("One MCP server package").version(version);
1034
+ program.addCommand(initCommand);
1035
+ program.addCommand(mcpServeCommand);
1036
+ program.addCommand(listToolsCommand);
1037
+ program.addCommand(describeToolsCommand);
1038
+ program.addCommand(useToolCommand);
1039
+ program.addCommand(prefetchCommand);
1040
+ await program.parseAsync(process.argv);
1041
+ } catch (error) {
1042
+ console.error(`CLI execution failed: ${error instanceof Error ? error.message : error}`);
1043
+ process.exit(1);
1044
+ }
585
1045
  }
586
- main();
1046
+ main().catch((error) => {
1047
+ console.error(`Fatal error: ${error instanceof Error ? error.message : error}`);
1048
+ process.exit(1);
1049
+ });
587
1050
 
588
1051
  //#endregion