frontmcp 0.4.0 → 0.5.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
@@ -1,9 +1,9 @@
1
1
  <div align="center">
2
2
 
3
3
  <picture>
4
- <source width="400" media="(prefers-color-scheme: dark)" srcset="docs/assets/logo/frontmcp.dark.svg">
5
- <source width="400" media="(prefers-color-scheme: light)" srcset="docs/assets/logo/frontmcp.light.svg">
6
- <img width="400" alt="FrontMCP Logo" src="docs/assets/logo/frontmcp.light.svg">
4
+ <source width="400" media="(prefers-color-scheme: dark)" srcset="docs/live/assets/logo/frontmcp.dark.svg">
5
+ <source width="400" media="(prefers-color-scheme: light)" srcset="docs/live/assets/logo/frontmcp.light.svg">
6
+ <img width="400" alt="FrontMCP Logo" src="docs/live/assets/logo/frontmcp.light.svg">
7
7
  </picture>
8
8
  <hr>
9
9
 
@@ -84,7 +84,13 @@ export default class Server {}
84
84
 
85
85
  ## Installation
86
86
 
87
- **Prereqs:** Node.js ≥ 22, npm ≥ 10. ([Installation - FrontMCP][1])
87
+ **Prerequisites:**
88
+
89
+ - **Node.js**: Minimum version 22 (LTS) | Recommended version 24 (Active LTS)
90
+ - _This framework is developed and tested on Node.js 24_
91
+ - **npm**: ≥ 10 (or pnpm/yarn equivalent)
92
+
93
+ For detailed setup instructions, see the [Installation Guide][1].
88
94
 
89
95
  ### Option A — New project (recommended)
90
96
 
@@ -98,7 +104,7 @@ installs required dev deps. ([Installation - FrontMCP][1])
98
104
  ### Option B — Add to an existing project
99
105
 
100
106
  ```bash
101
- npm i -D frontmcp @types/node@^20
107
+ npm i -D frontmcp @types/node@^22
102
108
  npx frontmcp init
103
109
  ```
104
110
 
@@ -295,31 +301,37 @@ FrontMCP][3])
295
301
 
296
302
  ### Servers
297
303
 
298
- `@FrontMcp({...})` defines **info**, **apps**, **http**, **logging**, **session**, and optional **auth**. Keep it
299
- minimal or scale up with providers and plugins. ([The FrontMCP Server - FrontMCP][5])
304
+ The FrontMCP server is defined with a single decorator: `@FrontMcp({...})`. It configures **info**, **apps**, **http**,
305
+ **logging**, **session**, and optional **auth**. Start minimal and scale up with providers and plugins.
306
+ ([The FrontMCP Server - FrontMCP][5])
300
307
 
301
308
  ### Apps
302
309
 
303
- Use `@App` to group **tools**, **resources**, **prompts**, plus **providers**, **adapters**, and **plugins**. With
304
- `splitByApp: true`, each app gets its own scope/base path and, if needed, its own auth surface. ([Apps - FrontMCP][6])
310
+ Apps are the **organizational units** for capabilities. Each app groups related **tools**, **resources**, and **prompts**
311
+ into a cohesive domain, along with **providers**, **adapters**, and **plugins**. With `splitByApp: true`, apps get
312
+ isolated scopes and auth surfaces. ([Apps - FrontMCP][6])
305
313
 
306
314
  ### Tools
307
315
 
308
- Typed actions with schemas (class `@Tool` or inline `tool({...})(handler)`). Use the Zod‑field **shape** style for
309
- `inputSchema`. ([Tools - FrontMCP][4])
316
+ Tools are **typed actions** that execute operations with side effects. They're the primary way to enable an AI model to
317
+ interact with external systems—calling APIs, modifying data, performing calculations, or triggering workflows. Use the
318
+ class `@Tool` decorator or inline `tool({...})(handler)` with Zod schemas. ([Tools - FrontMCP][4])
310
319
 
311
320
  ### Resources
312
321
 
313
- Readable data by URI or RFC6570 template (see `@Resource` / `@ResourceTemplate`). ([Resources - FrontMCP][7])
322
+ Resources expose **readable data** to an AI model's context. Unlike tools that execute actions with side effects,
323
+ resources are designed for read-only data retrieval—configuration files, user profiles, documents, or any content
324
+ the model needs to reference. ([Resources - FrontMCP][7])
314
325
 
315
326
  ### Prompts
316
327
 
317
- Reusable templates returning MCP `GetPromptResult`, with typed arguments. ([Prompts - FrontMCP][8])
328
+ Prompts provide **reusable message templates** for AI interactions. They return MCP `GetPromptResult` with typed
329
+ arguments, enabling consistent conversation patterns. ([Prompts - FrontMCP][8])
318
330
 
319
331
  ### Providers / Adapters / Plugins
320
332
 
321
- Inject shared services, generate tools from OpenAPI, and add cross‑cutting behavior like caching and hooks. ([Add
322
- OpenAPI Adapter - FrontMCP][9])
333
+ Inject shared services, generate tools from OpenAPI specs, and add cross‑cutting behavior like caching and hooks.
334
+ ([Add OpenAPI Adapter - FrontMCP][9])
323
335
 
324
336
  ---
325
337
 
@@ -442,7 +454,7 @@ See [LICENSE](./LICENSE).
442
454
  [7]: https://docs.agentfront.dev/docs/servers/resources 'Resources - FrontMCP'
443
455
  [8]: https://docs.agentfront.dev/docs/servers/prompts 'Prompts - FrontMCP'
444
456
  [9]: https://docs.agentfront.dev/docs/guides/add-openapi-adapter 'Add OpenAPI Adapter - FrontMCP'
445
- [10]: https://docs.agentfront.dev/docs/servers/authentication/overview 'Authentication - FrontMCP'
446
- [11]: https://docs.agentfront.dev/docs/servers/authentication/remote 'Remote OAuth - FrontMCP'
447
- [12]: https://docs.agentfront.dev/docs/servers/authentication/local 'Local OAuth - FrontMCP'
457
+ [10]: https://docs.agentfront.dev/docs/authentication/overview 'Authentication - FrontMCP'
458
+ [11]: https://docs.agentfront.dev/docs/authentication/remote 'Remote OAuth - FrontMCP'
459
+ [12]: https://docs.agentfront.dev/docs/authentication/local 'Local OAuth - FrontMCP'
448
460
  [13]: https://docs.agentfront.dev/docs/deployment/production-build 'Production Build - FrontMCP'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "frontmcp",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "FrontMCP command line interface",
5
5
  "author": "AgentFront <info@agentfront.dev>",
6
6
  "homepage": "https://docs.agentfront.dev",
@@ -15,7 +15,8 @@
15
15
  ],
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "git+https://github.com/agentfront/frontmcp.git"
18
+ "url": "git+https://github.com/agentfront/frontmcp.git",
19
+ "directory": "libs/cli"
19
20
  },
20
21
  "bugs": {
21
22
  "url": "https://github.com/agentfront/frontmcp/issues"
@@ -25,14 +26,14 @@
25
26
  "frontmcp": "./src/cli.js"
26
27
  },
27
28
  "dependencies": {
28
- "@frontmcp/sdk": "^0.4.0",
29
- "@frontmcp/plugins": "^0.4.0",
30
- "@frontmcp/adapters": "^0.4.0"
29
+ "@frontmcp/sdk": "0.5.0",
30
+ "@frontmcp/plugins": "0.5.0",
31
+ "@frontmcp/adapters": "0.5.0"
31
32
  },
32
33
  "devDependencies": {
33
34
  "typescript": "^5.5.3",
34
35
  "tsx": "^4.20.6",
35
- "@types/node": "^22.0.0",
36
+ "@types/node": "^24.0.0",
36
37
  "@modelcontextprotocol/inspector": "^0.17.2"
37
38
  },
38
39
  "types": "./src/index.d.ts",
package/src/args.d.ts CHANGED
@@ -1,8 +1,12 @@
1
- export type Command = 'dev' | 'build' | 'init' | 'doctor' | 'inspector' | 'create' | 'help' | 'template' | 'version';
1
+ export type Command = 'dev' | 'build' | 'init' | 'doctor' | 'inspector' | 'create' | 'help' | 'template' | 'version' | 'test';
2
2
  export interface ParsedArgs {
3
3
  _: string[];
4
4
  outDir?: string;
5
5
  entry?: string;
6
6
  help?: boolean;
7
+ runInBand?: boolean;
8
+ watch?: boolean;
9
+ verbose?: boolean;
10
+ timeout?: number;
7
11
  }
8
12
  export declare function parseArgs(argv: string[]): ParsedArgs;
package/src/args.js CHANGED
@@ -11,6 +11,16 @@ function parseArgs(argv) {
11
11
  out.entry = argv[++i];
12
12
  else if (a === '--help' || a === '-h')
13
13
  out.help = true;
14
+ else if (a === '--runInBand' || a === '-i')
15
+ out.runInBand = true;
16
+ else if (a === '--watch' || a === '-w')
17
+ out.watch = true;
18
+ else if (a === '--verbose' || a === '-v')
19
+ out.verbose = true;
20
+ else if (a === '--timeout' || a === '-t') {
21
+ const parsed = parseInt(argv[++i], 10);
22
+ out.timeout = Number.isNaN(parsed) ? undefined : parsed;
23
+ }
14
24
  else
15
25
  out._.push(a);
16
26
  }
package/src/args.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/args.ts"],"names":[],"mappings":";;AASA,8BAUC;AAVD,SAAgB,SAAS,CAAC,IAAc;IACtC,MAAM,GAAG,GAAe,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACvD,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACzD,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;;YAClD,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["export type Command = 'dev' | 'build' | 'init' | 'doctor' | 'inspector' | 'create' | 'help' | 'template' | 'version';\n\nexport interface ParsedArgs {\n _: string[];\n outDir?: string;\n entry?: string;\n help?: boolean;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--out-dir' || a === '-o') out.outDir = argv[++i];\n else if (a === '--entry' || a === '-e') out.entry = argv[++i];\n else if (a === '--help' || a === '-h') out.help = true;\n else out._.push(a);\n }\n return out;\n}\n"]}
1
+ {"version":3,"file":"args.js","sourceRoot":"","sources":["../../src/args.ts"],"names":[],"mappings":";;AAuBA,8BAgBC;AAhBD,SAAgB,SAAS,CAAC,IAAc;IACtC,MAAM,GAAG,GAAe,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACvD,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACzD,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;aAClD,IAAI,CAAC,KAAK,aAAa,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC;aAC5D,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC;aACpD,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI;YAAE,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;aACxD,IAAI,CAAC,KAAK,WAAW,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACvC,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;QAC1D,CAAC;;YAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["export type Command =\n | 'dev'\n | 'build'\n | 'init'\n | 'doctor'\n | 'inspector'\n | 'create'\n | 'help'\n | 'template'\n | 'version'\n | 'test';\n\nexport interface ParsedArgs {\n _: string[];\n outDir?: string;\n entry?: string;\n help?: boolean;\n runInBand?: boolean;\n watch?: boolean;\n verbose?: boolean;\n timeout?: number;\n}\n\nexport function parseArgs(argv: string[]): ParsedArgs {\n const out: ParsedArgs = { _: [] };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n if (a === '--out-dir' || a === '-o') out.outDir = argv[++i];\n else if (a === '--entry' || a === '-e') out.entry = argv[++i];\n else if (a === '--help' || a === '-h') out.help = true;\n else if (a === '--runInBand' || a === '-i') out.runInBand = true;\n else if (a === '--watch' || a === '-w') out.watch = true;\n else if (a === '--verbose' || a === '-v') out.verbose = true;\n else if (a === '--timeout' || a === '-t') {\n const parsed = parseInt(argv[++i], 10);\n out.timeout = Number.isNaN(parsed) ? undefined : parsed;\n } else out._.push(a);\n }\n return out;\n}\n"]}
package/src/cli.js CHANGED
@@ -13,6 +13,7 @@ const doctor_1 = require("./commands/doctor");
13
13
  const inspector_1 = require("./commands/inspector");
14
14
  const create_1 = require("./commands/create");
15
15
  const template_1 = require("./commands/template");
16
+ const test_1 = require("./commands/test");
16
17
  function showHelp() {
17
18
  console.log(`
18
19
  ${(0, colors_1.c)('bold', 'frontmcp')} — FrontMCP command line interface
@@ -23,6 +24,7 @@ ${(0, colors_1.c)('bold', 'Usage')}
23
24
  ${(0, colors_1.c)('bold', 'Commands')}
24
25
  dev Start in development mode (tsx --watch <entry> + async type-check)
25
26
  build Compile entry with TypeScript (tsc)
27
+ test Run E2E tests with auto-injected Jest configuration
26
28
  init Create or fix a tsconfig.json suitable for FrontMCP
27
29
  doctor Check Node/npm versions and tsconfig requirements
28
30
  inspector Launch MCP Inspector (npx @modelcontextprotocol/inspector)
@@ -34,9 +36,16 @@ ${(0, colors_1.c)('bold', 'Options')}
34
36
  -o, --out-dir <dir> Output directory (default: ./dist)
35
37
  -e, --entry <path> Manually specify entry file path
36
38
 
39
+ ${(0, colors_1.c)('bold', 'Test Options')}
40
+ -i, --runInBand Run tests sequentially (recommended for E2E)
41
+ -w, --watch Run tests in watch mode
42
+ -v, --verbose Show verbose test output
43
+ -t, --timeout <ms> Set test timeout (default: 60000ms)
44
+
37
45
  ${(0, colors_1.c)('bold', 'Examples')}
38
46
  frontmcp dev
39
47
  frontmcp build --out-dir build
48
+ frontmcp test --runInBand
40
49
  frontmcp init
41
50
  frontmcp doctor
42
51
  frontmcp inspector
@@ -80,6 +89,9 @@ async function main() {
80
89
  await (0, template_1.runTemplate)(type);
81
90
  break;
82
91
  }
92
+ case 'test':
93
+ await (0, test_1.runTest)(parsed);
94
+ break;
83
95
  case 'help':
84
96
  showHelp();
85
97
  break;
package/src/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";;AACA;;GAEG;;AAEH,qCAA6B;AAC7B,iCAAwD;AACxD,wCAAwC;AACxC,4CAA4C;AAC5C,yCAAqC;AACrC,8CAA8C;AAC9C,oDAAoD;AACpD,8CAA8C;AAC9C,kDAAkD;AAElD,SAAS,QAAQ;IACf,OAAO,CAAC,GAAG,CAAC;EACZ,IAAA,UAAC,EAAC,MAAM,EAAE,UAAU,CAAC;;EAErB,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC;;;EAGlB,IAAA,UAAC,EAAC,MAAM,EAAE,UAAU,CAAC;;;;;;;;;;EAUrB,IAAA,UAAC,EAAC,MAAM,EAAE,SAAS,CAAC;;;;EAIpB,IAAA,UAAC,EAAC,MAAM,EAAE,UAAU,CAAC;;;;;;;;CAQtB,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,MAAM,GAAe,IAAA,gBAAS,EAAC,IAAI,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAwB,CAAC;IAE/C,IAAI,MAAM,CAAC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;QACxB,QAAQ,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,KAAK;gBACR,MAAM,IAAA,YAAM,EAAC,MAAM,CAAC,CAAC;gBACrB,MAAM;YACR,KAAK,OAAO;gBACV,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC;gBACxC,MAAM,IAAA,gBAAQ,EAAC,MAAM,CAAC,CAAC;gBACvB,MAAM;YACR,KAAK,MAAM;gBACT,MAAM,IAAA,kBAAO,GAAE,CAAC;gBAChB,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,IAAA,kBAAS,GAAE,CAAC;gBAClB,MAAM;YACR,KAAK,WAAW;gBACd,MAAM,IAAA,wBAAY,GAAE,CAAC;gBACrB,MAAM;YACR,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,WAAW,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChC,MAAM,IAAA,kBAAS,EAAC,WAAW,CAAC,CAAC;gBAC7B,MAAM;YACR,CAAC;YACD,KAAK,UAAU,CAAC,CAAC,CAAC;gBAChB,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,+BAA+B;gBACzD,MAAM,IAAA,sBAAW,EAAC,IAAI,CAAC,CAAC;gBACxB,MAAM;YACR,CAAC;YACD,KAAK,MAAM;gBACT,QAAQ,EAAE,CAAC;gBACX,MAAM;YACR;gBACE,OAAO,CAAC,KAAK,CAAC,IAAA,UAAC,EAAC,KAAK,EAAE,oBAAoB,GAAG,EAAE,CAAC,CAAC,CAAC;gBACnD,QAAQ,EAAE,CAAC;gBACX,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,IAAI,GAAG,IAAA,UAAC,EAAC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC9F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC","sourcesContent":["#!/usr/bin/env node\n/**\n * frontmcp - FrontMCP command line interface\n */\n\nimport { c } from './colors';\nimport { Command, ParsedArgs, parseArgs } from './args';\nimport { runDev } from './commands/dev';\nimport { runBuild } from './commands/build';\nimport { runInit } from './tsconfig';\nimport { runDoctor } from './commands/doctor';\nimport { runInspector } from './commands/inspector';\nimport { runCreate } from './commands/create';\nimport { runTemplate } from './commands/template';\n\nfunction showHelp(): void {\n console.log(`\n${c('bold', 'frontmcp')} — FrontMCP command line interface\n\n${c('bold', 'Usage')}\n frontmcp <command> [options]\n\n${c('bold', 'Commands')}\n dev Start in development mode (tsx --watch <entry> + async type-check)\n build Compile entry with TypeScript (tsc)\n init Create or fix a tsconfig.json suitable for FrontMCP\n doctor Check Node/npm versions and tsconfig requirements\n inspector Launch MCP Inspector (npx @modelcontextprotocol/inspector)\n create <name> Scaffold a new FrontMCP project in ./<name>\n template <type> Scaffold a template by type (e.g., \"3rd-party-integration\")\n help Show this help message\n\n${c('bold', 'Options')}\n -o, --out-dir <dir> Output directory (default: ./dist)\n -e, --entry <path> Manually specify entry file path\n\n${c('bold', 'Examples')}\n frontmcp dev\n frontmcp build --out-dir build\n frontmcp init\n frontmcp doctor\n frontmcp inspector\n npx frontmcp create my-mcp\n npx frontmcp template marketplace-3rd-tools\n`);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const parsed: ParsedArgs = parseArgs(argv);\n const cmd = parsed._[0] as Command | undefined;\n\n if (parsed.help || !cmd) {\n showHelp();\n process.exit(0);\n }\n\n try {\n switch (cmd) {\n case 'dev':\n await runDev(parsed);\n break;\n case 'build':\n parsed.outDir = parsed.outDir || 'dist';\n await runBuild(parsed);\n break;\n case 'init':\n await runInit();\n break;\n case 'doctor':\n await runDoctor();\n break;\n case 'inspector':\n await runInspector();\n break;\n case 'create': {\n const projectName = parsed._[1];\n await runCreate(projectName);\n break;\n }\n case 'template': {\n const type = parsed._[1]; // e.g. \"3rd-party-integration\"\n await runTemplate(type);\n break;\n }\n case 'help':\n showHelp();\n break;\n default:\n console.error(c('red', `Unknown command: ${cmd}`));\n showHelp();\n process.exitCode = 1;\n }\n } catch (err: any) {\n console.error('\\n' + c('red', err instanceof Error ? err.stack || err.message : String(err)));\n process.exit(1);\n }\n}\n\nmain();\n"]}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":"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","sourcesContent":["#!/usr/bin/env node\n/**\n * frontmcp - FrontMCP command line interface\n */\n\nimport { c } from './colors';\nimport { Command, ParsedArgs, parseArgs } from './args';\nimport { runDev } from './commands/dev';\nimport { runBuild } from './commands/build';\nimport { runInit } from './tsconfig';\nimport { runDoctor } from './commands/doctor';\nimport { runInspector } from './commands/inspector';\nimport { runCreate } from './commands/create';\nimport { runTemplate } from './commands/template';\nimport { runTest } from './commands/test';\n\nfunction showHelp(): void {\n console.log(`\n${c('bold', 'frontmcp')} — FrontMCP command line interface\n\n${c('bold', 'Usage')}\n frontmcp <command> [options]\n\n${c('bold', 'Commands')}\n dev Start in development mode (tsx --watch <entry> + async type-check)\n build Compile entry with TypeScript (tsc)\n test Run E2E tests with auto-injected Jest configuration\n init Create or fix a tsconfig.json suitable for FrontMCP\n doctor Check Node/npm versions and tsconfig requirements\n inspector Launch MCP Inspector (npx @modelcontextprotocol/inspector)\n create <name> Scaffold a new FrontMCP project in ./<name>\n template <type> Scaffold a template by type (e.g., \"3rd-party-integration\")\n help Show this help message\n\n${c('bold', 'Options')}\n -o, --out-dir <dir> Output directory (default: ./dist)\n -e, --entry <path> Manually specify entry file path\n\n${c('bold', 'Test Options')}\n -i, --runInBand Run tests sequentially (recommended for E2E)\n -w, --watch Run tests in watch mode\n -v, --verbose Show verbose test output\n -t, --timeout <ms> Set test timeout (default: 60000ms)\n\n${c('bold', 'Examples')}\n frontmcp dev\n frontmcp build --out-dir build\n frontmcp test --runInBand\n frontmcp init\n frontmcp doctor\n frontmcp inspector\n npx frontmcp create my-mcp\n npx frontmcp template marketplace-3rd-tools\n`);\n}\n\nasync function main(): Promise<void> {\n const argv = process.argv.slice(2);\n const parsed: ParsedArgs = parseArgs(argv);\n const cmd = parsed._[0] as Command | undefined;\n\n if (parsed.help || !cmd) {\n showHelp();\n process.exit(0);\n }\n\n try {\n switch (cmd) {\n case 'dev':\n await runDev(parsed);\n break;\n case 'build':\n parsed.outDir = parsed.outDir || 'dist';\n await runBuild(parsed);\n break;\n case 'init':\n await runInit();\n break;\n case 'doctor':\n await runDoctor();\n break;\n case 'inspector':\n await runInspector();\n break;\n case 'create': {\n const projectName = parsed._[1];\n await runCreate(projectName);\n break;\n }\n case 'template': {\n const type = parsed._[1]; // e.g. \"3rd-party-integration\"\n await runTemplate(type);\n break;\n }\n case 'test':\n await runTest(parsed);\n break;\n case 'help':\n showHelp();\n break;\n default:\n console.error(c('red', `Unknown command: ${cmd}`));\n showHelp();\n process.exitCode = 1;\n }\n } catch (err: unknown) {\n console.error('\\n' + c('red', err instanceof Error ? err.stack || err.message : String(err)));\n process.exit(1);\n }\n}\n\nmain();\n"]}
@@ -35,7 +35,7 @@ function pkgNameFromCwd(cwd) {
35
35
  async function upsertPackageJson(cwd, nameOverride, selfVersion) {
36
36
  const pkgPath = path.join(cwd, 'package.json');
37
37
  const existing = await (0, fs_3.readJSON)(pkgPath);
38
- const frontmcpLibRange = `^${selfVersion}`;
38
+ const frontmcpLibRange = `~${selfVersion}`;
39
39
  const base = {
40
40
  name: nameOverride ?? pkgNameFromCwd(cwd),
41
41
  version: '0.1.0',
@@ -47,6 +47,7 @@ async function upsertPackageJson(cwd, nameOverride, selfVersion) {
47
47
  build: 'frontmcp build',
48
48
  inspect: 'frontmcp inspector',
49
49
  doctor: 'frontmcp doctor',
50
+ 'test:e2e': 'jest --config jest.e2e.config.ts --runInBand',
50
51
  },
51
52
  engines: {
52
53
  node: '>=22',
@@ -61,8 +62,12 @@ async function upsertPackageJson(cwd, nameOverride, selfVersion) {
61
62
  },
62
63
  devDependencies: {
63
64
  frontmcp: selfVersion,
65
+ '@frontmcp/testing': frontmcpLibRange,
66
+ '@swc/core': '^1.11.29',
67
+ '@swc/jest': '^0.2.37',
68
+ jest: '^29.7.0',
64
69
  tsx: '^4.20.6',
65
- '@types/node': '^22.0.0',
70
+ '@types/node': '^24.0.0',
66
71
  typescript: '^5.5.3',
67
72
  },
68
73
  };
@@ -82,6 +87,7 @@ async function upsertPackageJson(cwd, nameOverride, selfVersion) {
82
87
  build: existing.scripts?.build ?? base.scripts.build,
83
88
  inspect: existing.scripts?.inspect ?? base.scripts.inspect,
84
89
  doctor: existing.scripts?.doctor ?? base.scripts.doctor,
90
+ 'test:e2e': existing.scripts?.['test:e2e'] ?? base.scripts['test:e2e'],
85
91
  };
86
92
  merged.engines = {
87
93
  ...(existing.engines || {}),
@@ -156,6 +162,70 @@ export default class AddTool extends ToolContext {
156
162
  }
157
163
  }
158
164
  `;
165
+ const TEMPLATE_E2E_TEST_TS = `
166
+ import { test, expect } from '@frontmcp/testing';
167
+
168
+ test.describe('Server E2E', () => {
169
+ test.use({
170
+ server: './src/main.ts',
171
+ port: 3100,
172
+ });
173
+
174
+ test('should connect and initialize', async ({ mcp }) => {
175
+ expect(mcp.isConnected()).toBe(true);
176
+ expect(mcp.serverInfo.name).toBeDefined();
177
+ });
178
+
179
+ test('should list tools', async ({ mcp }) => {
180
+ const tools = await mcp.tools.list();
181
+ expect(tools.length).toBeGreaterThanOrEqual(0);
182
+ });
183
+
184
+ test('should call add tool', async ({ mcp }) => {
185
+ const result = await mcp.tools.call('add', { a: 2, b: 3 });
186
+ expect(result).toBeSuccessful();
187
+ });
188
+ });
189
+ `;
190
+ const TEMPLATE_JEST_E2E_CONFIG = `
191
+ /* eslint-disable */
192
+ export default {
193
+ displayName: 'e2e',
194
+ testEnvironment: 'node',
195
+ testMatch: ['<rootDir>/e2e/**/*.e2e.test.ts'],
196
+ testTimeout: 60000,
197
+ setupFilesAfterEnv: ['@frontmcp/testing/setup'],
198
+ transform: {
199
+ '^.+\\\\.[tj]s$': [
200
+ '@swc/jest',
201
+ {
202
+ jsc: {
203
+ target: 'es2022',
204
+ parser: {
205
+ syntax: 'typescript',
206
+ decorators: true,
207
+ dynamicImport: true,
208
+ },
209
+ transform: {
210
+ decoratorMetadata: true,
211
+ legacyDecorator: true,
212
+ },
213
+ keepClassNames: true,
214
+ externalHelpers: true,
215
+ loose: true,
216
+ },
217
+ module: {
218
+ type: 'es6',
219
+ },
220
+ sourceMaps: true,
221
+ swcrc: false,
222
+ },
223
+ ],
224
+ },
225
+ moduleFileExtensions: ['ts', 'js', 'html'],
226
+ transformIgnorePatterns: ['node_modules/(?!(jose)/)'],
227
+ };
228
+ `;
159
229
  async function runCreate(projectArg) {
160
230
  if (!projectArg) {
161
231
  console.error((0, colors_1.c)('red', 'Error: project name is required.\n'));
@@ -194,11 +264,15 @@ async function runCreate(projectArg) {
194
264
  await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'main.ts'), TEMPLATE_MAIN_TS);
195
265
  await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'calc.app.ts'), TEMPLATE_CALC_APP_TS);
196
266
  await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'tools', 'add.tool.ts'), TEMPLATE_ADD_TOOL_TS);
267
+ // E2E scaffolding
268
+ await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'e2e', 'server.e2e.test.ts'), TEMPLATE_E2E_TEST_TS);
269
+ await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'jest.e2e.config.ts'), TEMPLATE_JEST_E2E_CONFIG);
197
270
  console.log('\nNext steps:');
198
271
  console.log(` 1) cd ${folder}`);
199
272
  console.log(' 2) npm install');
200
- console.log(' 3) npm run dev ', (0, colors_1.c)('gray', '# tsx watcher + async tsc type-check'));
201
- console.log(' 4) npm run inspect ', (0, colors_1.c)('gray', '# launch MCP Inspector'));
202
- console.log(' 5) npm run build ', (0, colors_1.c)('gray', '# compile with tsc via frontmcp build'));
273
+ console.log(' 3) npm run dev ', (0, colors_1.c)('gray', '# tsx watcher + async tsc type-check'));
274
+ console.log(' 4) npm run inspect ', (0, colors_1.c)('gray', '# launch MCP Inspector'));
275
+ console.log(' 5) npm run build ', (0, colors_1.c)('gray', '# compile with tsc via frontmcp build'));
276
+ console.log(' 6) npm run test:e2e ', (0, colors_1.c)('gray', '# run E2E tests'));
203
277
  }
204
278
  //# sourceMappingURL=create.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { promises as fsp } from 'fs';\nimport { c } from '../colors';\nimport { ensureDir, fileExists, isDirEmpty, writeJSON } from '../utils/fs';\nimport { runInit } from '../tsconfig';\nimport { getSelfVersion } from '../version';\nimport { readJSON } from '../utils/fs';\n\nfunction sanitizeForFolder(name: string): string {\n const seg = name.startsWith('@') && name.includes('/') ? name.split('/')[1] : name;\n return (\n seg\n .replace(/[^a-zA-Z0-9._-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase() || 'frontmcp-app'\n );\n}\n\nfunction sanitizeForNpm(name: string): string {\n if (name.startsWith('@') && name.includes('/')) {\n const [scope, pkg] = name.split('/');\n const s = scope.replace(/[^a-z0-9-]/gi, '').toLowerCase();\n const p = pkg.replace(/[^a-z0-9._-]/gi, '-').toLowerCase();\n return `@${s}/${p || 'frontmcp-app'}`;\n }\n return name.replace(/[^a-z0-9._-]/gi, '-').toLowerCase() || 'frontmcp-app';\n}\n\nfunction pkgNameFromCwd(cwd: string) {\n return (\n path\n .basename(cwd)\n .replace(/[^a-zA-Z0-9._-]/g, '-')\n .toLowerCase() || 'frontmcp-app'\n );\n}\n\nasync function upsertPackageJson(cwd: string, nameOverride: string | undefined, selfVersion: string) {\n const pkgPath = path.join(cwd, 'package.json');\n const existing = await readJSON<Record<string, any>>(pkgPath);\n\n const frontmcpLibRange = `^${selfVersion}`;\n\n const base = {\n name: nameOverride ?? pkgNameFromCwd(cwd),\n version: '0.1.0',\n private: true,\n type: 'commonjs',\n main: 'src/main.ts',\n scripts: {\n dev: 'frontmcp dev',\n build: 'frontmcp build',\n inspect: 'frontmcp inspector',\n doctor: 'frontmcp doctor',\n },\n engines: {\n node: '>=22',\n npm: '>=10',\n },\n dependencies: {\n '@frontmcp/sdk': frontmcpLibRange,\n '@frontmcp/plugins': frontmcpLibRange,\n '@frontmcp/adapters': frontmcpLibRange,\n zod: '^3.25.76',\n 'reflect-metadata': '^0.2.2',\n },\n devDependencies: {\n frontmcp: selfVersion,\n tsx: '^4.20.6',\n '@types/node': '^22.0.0',\n typescript: '^5.5.3',\n },\n };\n\n if (!existing) {\n await writeJSON(pkgPath, base);\n console.log(c('green', '✅ Created package.json (synced @frontmcp libs to CLI version + exact frontmcp)'));\n return;\n }\n\n const merged: any = { ...base, ...existing };\n\n merged.name = existing.name || base.name;\n merged.main = existing.main || base.main;\n merged.type = existing.type || base.type;\n\n merged.scripts = {\n ...base.scripts,\n ...(existing.scripts || {}),\n dev: existing.scripts?.dev ?? base.scripts.dev,\n build: existing.scripts?.build ?? base.scripts.build,\n inspect: existing.scripts?.inspect ?? base.scripts.inspect,\n doctor: existing.scripts?.doctor ?? base.scripts.doctor,\n };\n\n merged.engines = {\n ...(existing.engines || {}),\n node: existing.engines?.node || base.engines.node,\n npm: existing.engines?.npm || base.engines.npm,\n };\n\n merged.dependencies = {\n ...(existing.dependencies || {}),\n ...base.dependencies,\n '@frontmcp/sdk': frontmcpLibRange,\n '@frontmcp/plugins': frontmcpLibRange,\n '@frontmcp/adapters': frontmcpLibRange,\n zod: '^3.25.76',\n 'reflect-metadata': '^0.2.2',\n };\n\n merged.devDependencies = {\n ...(existing.devDependencies || {}),\n ...base.devDependencies,\n frontmcp: selfVersion,\n tsx: '^4.20.6',\n typescript: '^5.5.3',\n };\n\n await writeJSON(pkgPath, merged);\n console.log(c('green', '✅ Updated package.json (synced @frontmcp libs + frontmcp to current CLI version)'));\n}\n\nasync function scaffoldFileIfMissing(baseDir: string, p: string, content: string) {\n if (await fileExists(p)) {\n console.log(c('gray', `skip: ${path.relative(baseDir, p)} already exists`));\n return;\n }\n await ensureDir(path.dirname(p));\n await fsp.writeFile(p, content.replace(/^\\n/, ''), 'utf8');\n console.log(c('green', `✓ created ${path.relative(baseDir, p)}`));\n}\n\nconst TEMPLATE_MAIN_TS = `\nimport 'reflect-metadata';\nimport { FrontMcp } from '@frontmcp/sdk';\nimport { CalcApp } from './calc.app';\n\n@FrontMcp({\n info: { name: 'Demo 🚀', version: '0.1.0' },\n apps: [CalcApp],\n})\nexport default class Server {}\n`;\n\nconst TEMPLATE_CALC_APP_TS = `\nimport { App } from '@frontmcp/sdk';\nimport AddTool from './tools/add.tool';\n\n@App({\n id: 'calc',\n name: 'Calculator',\n tools: [AddTool],\n})\nexport class CalcApp {}\n`;\n\nconst TEMPLATE_ADD_TOOL_TS = `\nimport {Tool, ToolContext} from \"@frontmcp/sdk\";\nimport {z} from \"zod\";\n\n@Tool({\n name: 'add',\n description: 'Add two numbers',\n inputSchema: {a: z.number(), b: z.number()},\n outputSchema: {result: z.number()}\n})\nexport default class AddTool extends ToolContext {\n async execute(input: { a: number, b: number }) {\n return {\n result: input.a + input.b,\n };\n }\n}\n`;\n\nexport async function runCreate(projectArg?: string): Promise<void> {\n if (!projectArg) {\n console.error(c('red', 'Error: project name is required.\\n'));\n console.log(`Usage: ${c('bold', 'npx frontmcp create <project-name>')}`);\n process.exit(1);\n }\n\n const folder = sanitizeForFolder(projectArg);\n const pkgName = sanitizeForNpm(projectArg);\n const targetDir = path.resolve(process.cwd(), folder);\n\n try {\n const stat = await fsp.stat(targetDir);\n if (!stat.isDirectory()) {\n console.error(\n c('red', `Refusing to scaffold into non-directory path: ${path.relative(process.cwd(), targetDir)}`),\n );\n console.log(c('gray', 'Pick a different project name or remove/rename the existing file.'));\n process.exit(1);\n }\n if (!(await isDirEmpty(targetDir))) {\n console.error(\n c('red', `Refusing to scaffold into non-empty directory: ${path.relative(process.cwd(), targetDir)}`),\n );\n console.log(c('gray', 'Pick a different name or start with an empty folder.'));\n process.exit(1);\n }\n } catch (e: any) {\n if (e?.code === 'ENOENT') {\n await ensureDir(targetDir);\n } else {\n throw e;\n }\n }\n\n console.log(\n `${c('cyan', '[create]')} Creating project in ${c('bold', './' + path.relative(process.cwd(), targetDir))}`,\n );\n process.chdir(targetDir);\n\n await runInit(targetDir);\n\n const selfVersion = getSelfVersion();\n await upsertPackageJson(targetDir, pkgName, selfVersion);\n\n await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'main.ts'), TEMPLATE_MAIN_TS);\n await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'calc.app.ts'), TEMPLATE_CALC_APP_TS);\n await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'tools', 'add.tool.ts'), TEMPLATE_ADD_TOOL_TS);\n\n console.log('\\nNext steps:');\n console.log(` 1) cd ${folder}`);\n console.log(' 2) npm install');\n console.log(' 3) npm run dev ', c('gray', '# tsx watcher + async tsc type-check'));\n console.log(' 4) npm run inspect ', c('gray', '# launch MCP Inspector'));\n console.log(' 5) npm run build ', c('gray', '# compile with tsc via frontmcp build'));\n}\n"]}
1
+ {"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/create.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path';\nimport { promises as fsp } from 'fs';\nimport { c } from '../colors';\nimport { ensureDir, fileExists, isDirEmpty, writeJSON } from '../utils/fs';\nimport { runInit } from '../tsconfig';\nimport { getSelfVersion } from '../version';\nimport { readJSON } from '../utils/fs';\n\nfunction sanitizeForFolder(name: string): string {\n const seg = name.startsWith('@') && name.includes('/') ? name.split('/')[1] : name;\n return (\n seg\n .replace(/[^a-zA-Z0-9._-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n .toLowerCase() || 'frontmcp-app'\n );\n}\n\nfunction sanitizeForNpm(name: string): string {\n if (name.startsWith('@') && name.includes('/')) {\n const [scope, pkg] = name.split('/');\n const s = scope.replace(/[^a-z0-9-]/gi, '').toLowerCase();\n const p = pkg.replace(/[^a-z0-9._-]/gi, '-').toLowerCase();\n return `@${s}/${p || 'frontmcp-app'}`;\n }\n return name.replace(/[^a-z0-9._-]/gi, '-').toLowerCase() || 'frontmcp-app';\n}\n\nfunction pkgNameFromCwd(cwd: string) {\n return (\n path\n .basename(cwd)\n .replace(/[^a-zA-Z0-9._-]/g, '-')\n .toLowerCase() || 'frontmcp-app'\n );\n}\n\nasync function upsertPackageJson(cwd: string, nameOverride: string | undefined, selfVersion: string) {\n const pkgPath = path.join(cwd, 'package.json');\n const existing = await readJSON<Record<string, any>>(pkgPath);\n\n const frontmcpLibRange = `~${selfVersion}`;\n\n const base = {\n name: nameOverride ?? pkgNameFromCwd(cwd),\n version: '0.1.0',\n private: true,\n type: 'commonjs',\n main: 'src/main.ts',\n scripts: {\n dev: 'frontmcp dev',\n build: 'frontmcp build',\n inspect: 'frontmcp inspector',\n doctor: 'frontmcp doctor',\n 'test:e2e': 'jest --config jest.e2e.config.ts --runInBand',\n },\n engines: {\n node: '>=22',\n npm: '>=10',\n },\n dependencies: {\n '@frontmcp/sdk': frontmcpLibRange,\n '@frontmcp/plugins': frontmcpLibRange,\n '@frontmcp/adapters': frontmcpLibRange,\n zod: '^3.25.76',\n 'reflect-metadata': '^0.2.2',\n },\n devDependencies: {\n frontmcp: selfVersion,\n '@frontmcp/testing': frontmcpLibRange,\n '@swc/core': '^1.11.29',\n '@swc/jest': '^0.2.37',\n jest: '^29.7.0',\n tsx: '^4.20.6',\n '@types/node': '^24.0.0',\n typescript: '^5.5.3',\n },\n };\n\n if (!existing) {\n await writeJSON(pkgPath, base);\n console.log(c('green', '✅ Created package.json (synced @frontmcp libs to CLI version + exact frontmcp)'));\n return;\n }\n\n const merged: any = { ...base, ...existing };\n\n merged.name = existing.name || base.name;\n merged.main = existing.main || base.main;\n merged.type = existing.type || base.type;\n\n merged.scripts = {\n ...base.scripts,\n ...(existing.scripts || {}),\n dev: existing.scripts?.dev ?? base.scripts.dev,\n build: existing.scripts?.build ?? base.scripts.build,\n inspect: existing.scripts?.inspect ?? base.scripts.inspect,\n doctor: existing.scripts?.doctor ?? base.scripts.doctor,\n 'test:e2e': existing.scripts?.['test:e2e'] ?? base.scripts['test:e2e'],\n };\n\n merged.engines = {\n ...(existing.engines || {}),\n node: existing.engines?.node || base.engines.node,\n npm: existing.engines?.npm || base.engines.npm,\n };\n\n merged.dependencies = {\n ...(existing.dependencies || {}),\n ...base.dependencies,\n '@frontmcp/sdk': frontmcpLibRange,\n '@frontmcp/plugins': frontmcpLibRange,\n '@frontmcp/adapters': frontmcpLibRange,\n zod: '^3.25.76',\n 'reflect-metadata': '^0.2.2',\n };\n\n merged.devDependencies = {\n ...(existing.devDependencies || {}),\n ...base.devDependencies,\n frontmcp: selfVersion,\n tsx: '^4.20.6',\n typescript: '^5.5.3',\n };\n\n await writeJSON(pkgPath, merged);\n console.log(c('green', '✅ Updated package.json (synced @frontmcp libs + frontmcp to current CLI version)'));\n}\n\nasync function scaffoldFileIfMissing(baseDir: string, p: string, content: string) {\n if (await fileExists(p)) {\n console.log(c('gray', `skip: ${path.relative(baseDir, p)} already exists`));\n return;\n }\n await ensureDir(path.dirname(p));\n await fsp.writeFile(p, content.replace(/^\\n/, ''), 'utf8');\n console.log(c('green', `✓ created ${path.relative(baseDir, p)}`));\n}\n\nconst TEMPLATE_MAIN_TS = `\nimport 'reflect-metadata';\nimport { FrontMcp } from '@frontmcp/sdk';\nimport { CalcApp } from './calc.app';\n\n@FrontMcp({\n info: { name: 'Demo 🚀', version: '0.1.0' },\n apps: [CalcApp],\n})\nexport default class Server {}\n`;\n\nconst TEMPLATE_CALC_APP_TS = `\nimport { App } from '@frontmcp/sdk';\nimport AddTool from './tools/add.tool';\n\n@App({\n id: 'calc',\n name: 'Calculator',\n tools: [AddTool],\n})\nexport class CalcApp {}\n`;\n\nconst TEMPLATE_ADD_TOOL_TS = `\nimport {Tool, ToolContext} from \"@frontmcp/sdk\";\nimport {z} from \"zod\";\n\n@Tool({\n name: 'add',\n description: 'Add two numbers',\n inputSchema: {a: z.number(), b: z.number()},\n outputSchema: {result: z.number()}\n})\nexport default class AddTool extends ToolContext {\n async execute(input: { a: number, b: number }) {\n return {\n result: input.a + input.b,\n };\n }\n}\n`;\n\nconst TEMPLATE_E2E_TEST_TS = `\nimport { test, expect } from '@frontmcp/testing';\n\ntest.describe('Server E2E', () => {\n test.use({\n server: './src/main.ts',\n port: 3100,\n });\n\n test('should connect and initialize', async ({ mcp }) => {\n expect(mcp.isConnected()).toBe(true);\n expect(mcp.serverInfo.name).toBeDefined();\n });\n\n test('should list tools', async ({ mcp }) => {\n const tools = await mcp.tools.list();\n expect(tools.length).toBeGreaterThanOrEqual(0);\n });\n\n test('should call add tool', async ({ mcp }) => {\n const result = await mcp.tools.call('add', { a: 2, b: 3 });\n expect(result).toBeSuccessful();\n });\n});\n`;\n\nconst TEMPLATE_JEST_E2E_CONFIG = `\n/* eslint-disable */\nexport default {\n displayName: 'e2e',\n testEnvironment: 'node',\n testMatch: ['<rootDir>/e2e/**/*.e2e.test.ts'],\n testTimeout: 60000,\n setupFilesAfterEnv: ['@frontmcp/testing/setup'],\n transform: {\n '^.+\\\\\\\\.[tj]s$': [\n '@swc/jest',\n {\n jsc: {\n target: 'es2022',\n parser: {\n syntax: 'typescript',\n decorators: true,\n dynamicImport: true,\n },\n transform: {\n decoratorMetadata: true,\n legacyDecorator: true,\n },\n keepClassNames: true,\n externalHelpers: true,\n loose: true,\n },\n module: {\n type: 'es6',\n },\n sourceMaps: true,\n swcrc: false,\n },\n ],\n },\n moduleFileExtensions: ['ts', 'js', 'html'],\n transformIgnorePatterns: ['node_modules/(?!(jose)/)'],\n};\n`;\n\nexport async function runCreate(projectArg?: string): Promise<void> {\n if (!projectArg) {\n console.error(c('red', 'Error: project name is required.\\n'));\n console.log(`Usage: ${c('bold', 'npx frontmcp create <project-name>')}`);\n process.exit(1);\n }\n\n const folder = sanitizeForFolder(projectArg);\n const pkgName = sanitizeForNpm(projectArg);\n const targetDir = path.resolve(process.cwd(), folder);\n\n try {\n const stat = await fsp.stat(targetDir);\n if (!stat.isDirectory()) {\n console.error(\n c('red', `Refusing to scaffold into non-directory path: ${path.relative(process.cwd(), targetDir)}`),\n );\n console.log(c('gray', 'Pick a different project name or remove/rename the existing file.'));\n process.exit(1);\n }\n if (!(await isDirEmpty(targetDir))) {\n console.error(\n c('red', `Refusing to scaffold into non-empty directory: ${path.relative(process.cwd(), targetDir)}`),\n );\n console.log(c('gray', 'Pick a different name or start with an empty folder.'));\n process.exit(1);\n }\n } catch (e: any) {\n if (e?.code === 'ENOENT') {\n await ensureDir(targetDir);\n } else {\n throw e;\n }\n }\n\n console.log(\n `${c('cyan', '[create]')} Creating project in ${c('bold', './' + path.relative(process.cwd(), targetDir))}`,\n );\n process.chdir(targetDir);\n\n await runInit(targetDir);\n\n const selfVersion = getSelfVersion();\n await upsertPackageJson(targetDir, pkgName, selfVersion);\n\n await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'main.ts'), TEMPLATE_MAIN_TS);\n await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'calc.app.ts'), TEMPLATE_CALC_APP_TS);\n await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'src', 'tools', 'add.tool.ts'), TEMPLATE_ADD_TOOL_TS);\n\n // E2E scaffolding\n await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'e2e', 'server.e2e.test.ts'), TEMPLATE_E2E_TEST_TS);\n await scaffoldFileIfMissing(targetDir, path.join(targetDir, 'jest.e2e.config.ts'), TEMPLATE_JEST_E2E_CONFIG);\n\n console.log('\\nNext steps:');\n console.log(` 1) cd ${folder}`);\n console.log(' 2) npm install');\n console.log(' 3) npm run dev ', c('gray', '# tsx watcher + async tsc type-check'));\n console.log(' 4) npm run inspect ', c('gray', '# launch MCP Inspector'));\n console.log(' 5) npm run build ', c('gray', '# compile with tsc via frontmcp build'));\n console.log(' 6) npm run test:e2e ', c('gray', '# run E2E tests'));\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { ParsedArgs } from '../args';
2
+ /**
3
+ * Run E2E tests using Jest with auto-injected configuration.
4
+ *
5
+ * Usage:
6
+ * frontmcp test # Run E2E tests in current directory
7
+ * frontmcp test --runInBand # Run tests sequentially (recommended for E2E)
8
+ * frontmcp test --watch # Run tests in watch mode
9
+ * frontmcp test --verbose # Show verbose output
10
+ * frontmcp test --timeout 60000 # Set test timeout (default: 60000ms)
11
+ */
12
+ export declare function runTest(opts: ParsedArgs): Promise<void>;
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runTest = runTest;
4
+ const tslib_1 = require("tslib");
5
+ const path = tslib_1.__importStar(require("path"));
6
+ const os = tslib_1.__importStar(require("os"));
7
+ const child_process_1 = require("child_process");
8
+ const colors_1 = require("../colors");
9
+ const fs_1 = require("../utils/fs");
10
+ /**
11
+ * Generate Jest configuration programmatically for E2E tests.
12
+ * This eliminates the need for projects to have their own jest.e2e.config.ts.
13
+ */
14
+ function generateJestConfig(cwd, opts) {
15
+ const testTimeout = opts.timeout ?? 60000;
16
+ return {
17
+ // Use Node.js environment for E2E tests
18
+ testEnvironment: 'node',
19
+ // Root directory for tests
20
+ rootDir: cwd,
21
+ // Test file patterns for E2E tests
22
+ testMatch: ['<rootDir>/e2e/**/*.e2e.ts', '<rootDir>/e2e/**/*.e2e.test.ts', '<rootDir>/**/*.e2e.ts'],
23
+ // Transform TypeScript files using @swc/jest for speed
24
+ transform: {
25
+ '^.+\\.[tj]s$': [
26
+ '@swc/jest',
27
+ {
28
+ jsc: {
29
+ target: 'es2022',
30
+ parser: {
31
+ syntax: 'typescript',
32
+ decorators: true,
33
+ dynamicImport: true,
34
+ },
35
+ transform: {
36
+ decoratorMetadata: true,
37
+ legacyDecorator: true,
38
+ },
39
+ keepClassNames: true,
40
+ externalHelpers: true,
41
+ loose: true,
42
+ },
43
+ module: {
44
+ type: 'es6',
45
+ },
46
+ sourceMaps: true,
47
+ swcrc: false,
48
+ },
49
+ ],
50
+ },
51
+ // File extensions to consider
52
+ moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
53
+ // Test timeout
54
+ testTimeout,
55
+ // Setup files that run after Jest is initialized
56
+ setupFilesAfterEnv: ['@frontmcp/testing/setup'],
57
+ // Transform packages that use ESM
58
+ transformIgnorePatterns: ['node_modules/(?!(jose)/)'],
59
+ // Ignore patterns
60
+ testPathIgnorePatterns: ['/node_modules/', '/dist/'],
61
+ // Coverage settings (disabled by default for E2E)
62
+ collectCoverage: false,
63
+ // Verbose output
64
+ verbose: opts.verbose ?? true,
65
+ };
66
+ }
67
+ /**
68
+ * Run E2E tests using Jest with auto-injected configuration.
69
+ *
70
+ * Usage:
71
+ * frontmcp test # Run E2E tests in current directory
72
+ * frontmcp test --runInBand # Run tests sequentially (recommended for E2E)
73
+ * frontmcp test --watch # Run tests in watch mode
74
+ * frontmcp test --verbose # Show verbose output
75
+ * frontmcp test --timeout 60000 # Set test timeout (default: 60000ms)
76
+ */
77
+ async function runTest(opts) {
78
+ const cwd = process.cwd();
79
+ // Check for e2e directory
80
+ const e2eDir = path.join(cwd, 'e2e');
81
+ const hasE2EDir = await (0, fs_1.fileExists)(e2eDir);
82
+ if (!hasE2EDir) {
83
+ console.error((0, colors_1.c)('red', 'No e2e directory found.'));
84
+ console.error('');
85
+ console.error('Expected structure:');
86
+ console.error(' ./e2e/');
87
+ console.error(' ├── your-test.e2e.ts');
88
+ console.error(' └── another-test.e2e.test.ts');
89
+ console.error('');
90
+ console.error('Create an e2e directory with test files, then run:');
91
+ console.error(' frontmcp test');
92
+ process.exit(1);
93
+ }
94
+ // Generate Jest config and write to temp file
95
+ const config = generateJestConfig(cwd, opts);
96
+ const tempDir = os.tmpdir();
97
+ const configPath = path.join(tempDir, `frontmcp-jest-config-${Date.now()}.json`);
98
+ await fs_1.fsp.writeFile(configPath, JSON.stringify(config, null, 2));
99
+ // Build Jest arguments
100
+ const jestArgs = ['jest', '--config', configPath];
101
+ // Add --runInBand for sequential execution (recommended for E2E tests)
102
+ if (opts.runInBand) {
103
+ jestArgs.push('--runInBand');
104
+ }
105
+ // Add watch mode
106
+ if (opts.watch) {
107
+ jestArgs.push('--watch');
108
+ }
109
+ // Add verbose flag
110
+ if (opts.verbose) {
111
+ jestArgs.push('--verbose');
112
+ }
113
+ // Add any additional positional args (e.g., test file patterns)
114
+ const testPatterns = opts._.slice(1); // Skip 'test' command itself
115
+ if (testPatterns.length > 0) {
116
+ jestArgs.push(...testPatterns);
117
+ }
118
+ console.log(`${(0, colors_1.c)('cyan', '[test]')} running E2E tests in ${path.relative(process.cwd(), cwd) || '.'}`);
119
+ console.log(`${(0, colors_1.c)('gray', '[test]')} using auto-injected Jest configuration`);
120
+ if (opts.runInBand) {
121
+ console.log(`${(0, colors_1.c)('gray', '[test]')} running tests sequentially (--runInBand)`);
122
+ }
123
+ if (opts.watch) {
124
+ console.log(`${(0, colors_1.c)('gray', '[test]')} watch mode enabled`);
125
+ }
126
+ console.log(`${(0, colors_1.c)('gray', 'hint:')} press Ctrl+C to stop\n`);
127
+ // Run Jest directly via node_modules/.bin or npx without shell
128
+ // Using shell: false with explicit args array avoids escaping issues
129
+ const jest = (0, child_process_1.spawn)('npx', jestArgs, {
130
+ stdio: 'inherit',
131
+ shell: false,
132
+ cwd,
133
+ });
134
+ // Handle cleanup
135
+ const cleanup = async (proc) => {
136
+ try {
137
+ if (proc) {
138
+ proc.kill('SIGINT');
139
+ }
140
+ }
141
+ catch {
142
+ // ignore
143
+ }
144
+ // Clean up temp config file
145
+ try {
146
+ await fs_1.fsp.unlink(configPath);
147
+ }
148
+ catch {
149
+ // ignore
150
+ }
151
+ };
152
+ process.on('SIGINT', () => {
153
+ cleanup(jest).finally(() => {
154
+ process.exit(0);
155
+ });
156
+ });
157
+ // Wait for Jest to complete
158
+ try {
159
+ await new Promise((resolve, reject) => {
160
+ jest.on('close', (code) => {
161
+ if (code === 0) {
162
+ resolve();
163
+ }
164
+ else {
165
+ reject(new Error(`Jest exited with code ${code}`));
166
+ }
167
+ });
168
+ jest.on('error', (err) => {
169
+ reject(err);
170
+ });
171
+ });
172
+ }
173
+ finally {
174
+ // Clean up temp config file
175
+ try {
176
+ await fs_1.fsp.unlink(configPath);
177
+ }
178
+ catch {
179
+ // ignore
180
+ }
181
+ }
182
+ }
183
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../../src/commands/test.ts"],"names":[],"mappings":";;AAsFA,0BAoHC;;AA1MD,mDAA6B;AAC7B,+CAAyB;AACzB,iDAAoD;AAEpD,sCAA8B;AAC9B,oCAA8C;AAE9C;;;GAGG;AACH,SAAS,kBAAkB,CAAC,GAAW,EAAE,IAAgB;IACvD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IAE1C,OAAO;QACL,wCAAwC;QACxC,eAAe,EAAE,MAAM;QAEvB,2BAA2B;QAC3B,OAAO,EAAE,GAAG;QAEZ,mCAAmC;QACnC,SAAS,EAAE,CAAC,2BAA2B,EAAE,gCAAgC,EAAE,uBAAuB,CAAC;QAEnG,uDAAuD;QACvD,SAAS,EAAE;YACT,cAAc,EAAE;gBACd,WAAW;gBACX;oBACE,GAAG,EAAE;wBACH,MAAM,EAAE,QAAQ;wBAChB,MAAM,EAAE;4BACN,MAAM,EAAE,YAAY;4BACpB,UAAU,EAAE,IAAI;4BAChB,aAAa,EAAE,IAAI;yBACpB;wBACD,SAAS,EAAE;4BACT,iBAAiB,EAAE,IAAI;4BACvB,eAAe,EAAE,IAAI;yBACtB;wBACD,cAAc,EAAE,IAAI;wBACpB,eAAe,EAAE,IAAI;wBACrB,KAAK,EAAE,IAAI;qBACZ;oBACD,MAAM,EAAE;wBACN,IAAI,EAAE,KAAK;qBACZ;oBACD,UAAU,EAAE,IAAI;oBAChB,KAAK,EAAE,KAAK;iBACb;aACF;SACF;QAED,8BAA8B;QAC9B,oBAAoB,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC;QAEhE,eAAe;QACf,WAAW;QAEX,iDAAiD;QACjD,kBAAkB,EAAE,CAAC,yBAAyB,CAAC;QAE/C,kCAAkC;QAClC,uBAAuB,EAAE,CAAC,0BAA0B,CAAC;QAErD,kBAAkB;QAClB,sBAAsB,EAAE,CAAC,gBAAgB,EAAE,QAAQ,CAAC;QAEpD,kDAAkD;QAClD,eAAe,EAAE,KAAK;QAEtB,iBAAiB;QACjB,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,IAAI;KAC9B,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACI,KAAK,UAAU,OAAO,CAAC,IAAgB;IAC5C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAE1B,0BAA0B;IAC1B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,MAAM,IAAA,eAAU,EAAC,MAAM,CAAC,CAAC;IAE3C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,IAAA,UAAC,EAAC,KAAK,EAAE,yBAAyB,CAAC,CAAC,CAAC;QACnD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,CAAC;QACrC,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1B,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAClD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAClB,OAAO,CAAC,KAAK,CAAC,oDAAoD,CAAC,CAAC;QACpE,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,8CAA8C;IAC9C,MAAM,MAAM,GAAG,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC;IAC5B,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,wBAAwB,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IACjF,MAAM,QAAG,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAEjE,uBAAuB;IACvB,MAAM,QAAQ,GAAa,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;IAE5D,uEAAuE;IACvE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,QAAQ,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC/B,CAAC;IAED,iBAAiB;IACjB,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;IAED,mBAAmB;IACnB,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAC7B,CAAC;IAED,gEAAgE;IAChE,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,6BAA6B;IACnE,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,QAAQ,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,QAAQ,CAAC,yBAAyB,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACvG,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,QAAQ,CAAC,yCAAyC,CAAC,CAAC;IAE7E,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,QAAQ,CAAC,2CAA2C,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,QAAQ,CAAC,qBAAqB,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,GAAG,IAAA,UAAC,EAAC,MAAM,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAE5D,+DAA+D;IAC/D,qEAAqE;IACrE,MAAM,IAAI,GAAG,IAAA,qBAAK,EAAC,KAAK,EAAE,QAAQ,EAAE;QAClC,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,KAAK;QACZ,GAAG;KACJ,CAAC,CAAC;IAEH,iBAAiB;IACjB,MAAM,OAAO,GAAG,KAAK,EAAE,IAAmB,EAAE,EAAE;QAC5C,IAAI,CAAC;YACH,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,4BAA4B;QAC5B,IAAI,CAAC;YACH,MAAM,QAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;QACxB,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;YACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,4BAA4B;IAC5B,IAAI,CAAC;QACH,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACf,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC,CAAC;gBACrD,CAAC;YACH,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACvB,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,4BAA4B;QAC5B,IAAI,CAAC;YACH,MAAM,QAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["import * as path from 'path';\nimport * as os from 'os';\nimport { spawn, ChildProcess } from 'child_process';\nimport { ParsedArgs } from '../args';\nimport { c } from '../colors';\nimport { fileExists, fsp } from '../utils/fs';\n\n/**\n * Generate Jest configuration programmatically for E2E tests.\n * This eliminates the need for projects to have their own jest.e2e.config.ts.\n */\nfunction generateJestConfig(cwd: string, opts: ParsedArgs): object {\n const testTimeout = opts.timeout ?? 60000;\n\n return {\n // Use Node.js environment for E2E tests\n testEnvironment: 'node',\n\n // Root directory for tests\n rootDir: cwd,\n\n // Test file patterns for E2E tests\n testMatch: ['<rootDir>/e2e/**/*.e2e.ts', '<rootDir>/e2e/**/*.e2e.test.ts', '<rootDir>/**/*.e2e.ts'],\n\n // Transform TypeScript files using @swc/jest for speed\n transform: {\n '^.+\\\\.[tj]s$': [\n '@swc/jest',\n {\n jsc: {\n target: 'es2022',\n parser: {\n syntax: 'typescript',\n decorators: true,\n dynamicImport: true,\n },\n transform: {\n decoratorMetadata: true,\n legacyDecorator: true,\n },\n keepClassNames: true,\n externalHelpers: true,\n loose: true,\n },\n module: {\n type: 'es6',\n },\n sourceMaps: true,\n swcrc: false,\n },\n ],\n },\n\n // File extensions to consider\n moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],\n\n // Test timeout\n testTimeout,\n\n // Setup files that run after Jest is initialized\n setupFilesAfterEnv: ['@frontmcp/testing/setup'],\n\n // Transform packages that use ESM\n transformIgnorePatterns: ['node_modules/(?!(jose)/)'],\n\n // Ignore patterns\n testPathIgnorePatterns: ['/node_modules/', '/dist/'],\n\n // Coverage settings (disabled by default for E2E)\n collectCoverage: false,\n\n // Verbose output\n verbose: opts.verbose ?? true,\n };\n}\n\n/**\n * Run E2E tests using Jest with auto-injected configuration.\n *\n * Usage:\n * frontmcp test # Run E2E tests in current directory\n * frontmcp test --runInBand # Run tests sequentially (recommended for E2E)\n * frontmcp test --watch # Run tests in watch mode\n * frontmcp test --verbose # Show verbose output\n * frontmcp test --timeout 60000 # Set test timeout (default: 60000ms)\n */\nexport async function runTest(opts: ParsedArgs): Promise<void> {\n const cwd = process.cwd();\n\n // Check for e2e directory\n const e2eDir = path.join(cwd, 'e2e');\n const hasE2EDir = await fileExists(e2eDir);\n\n if (!hasE2EDir) {\n console.error(c('red', 'No e2e directory found.'));\n console.error('');\n console.error('Expected structure:');\n console.error(' ./e2e/');\n console.error(' ├── your-test.e2e.ts');\n console.error(' └── another-test.e2e.test.ts');\n console.error('');\n console.error('Create an e2e directory with test files, then run:');\n console.error(' frontmcp test');\n process.exit(1);\n }\n\n // Generate Jest config and write to temp file\n const config = generateJestConfig(cwd, opts);\n const tempDir = os.tmpdir();\n const configPath = path.join(tempDir, `frontmcp-jest-config-${Date.now()}.json`);\n await fsp.writeFile(configPath, JSON.stringify(config, null, 2));\n\n // Build Jest arguments\n const jestArgs: string[] = ['jest', '--config', configPath];\n\n // Add --runInBand for sequential execution (recommended for E2E tests)\n if (opts.runInBand) {\n jestArgs.push('--runInBand');\n }\n\n // Add watch mode\n if (opts.watch) {\n jestArgs.push('--watch');\n }\n\n // Add verbose flag\n if (opts.verbose) {\n jestArgs.push('--verbose');\n }\n\n // Add any additional positional args (e.g., test file patterns)\n const testPatterns = opts._.slice(1); // Skip 'test' command itself\n if (testPatterns.length > 0) {\n jestArgs.push(...testPatterns);\n }\n\n console.log(`${c('cyan', '[test]')} running E2E tests in ${path.relative(process.cwd(), cwd) || '.'}`);\n console.log(`${c('gray', '[test]')} using auto-injected Jest configuration`);\n\n if (opts.runInBand) {\n console.log(`${c('gray', '[test]')} running tests sequentially (--runInBand)`);\n }\n\n if (opts.watch) {\n console.log(`${c('gray', '[test]')} watch mode enabled`);\n }\n\n console.log(`${c('gray', 'hint:')} press Ctrl+C to stop\\n`);\n\n // Run Jest directly via node_modules/.bin or npx without shell\n // Using shell: false with explicit args array avoids escaping issues\n const jest = spawn('npx', jestArgs, {\n stdio: 'inherit',\n shell: false,\n cwd,\n });\n\n // Handle cleanup\n const cleanup = async (proc?: ChildProcess) => {\n try {\n if (proc) {\n proc.kill('SIGINT');\n }\n } catch {\n // ignore\n }\n // Clean up temp config file\n try {\n await fsp.unlink(configPath);\n } catch {\n // ignore\n }\n };\n\n process.on('SIGINT', () => {\n cleanup(jest).finally(() => {\n process.exit(0);\n });\n });\n\n // Wait for Jest to complete\n try {\n await new Promise<void>((resolve, reject) => {\n jest.on('close', (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Jest exited with code ${code}`));\n }\n });\n jest.on('error', (err) => {\n reject(err);\n });\n });\n } finally {\n // Clean up temp config file\n try {\n await fsp.unlink(configPath);\n } catch {\n // ignore\n }\n }\n}\n"]}
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HttpClient = void 0;
4
4
  class HttpClient {
5
+ ctx;
5
6
  constructor(ctx) {
6
7
  this.ctx = ctx;
7
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../../../../src/templates/3rd-party-integration/src/http-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { ExecuteContext } from \"./mcp-http-types\";\n\nexport interface HttpRequestOptions {\n method: string;\n path: string; // already resolved (including path params)\n query?: Record<string, string | number | boolean | undefined>;\n headers?: Record<string, string>;\n bodyJson?: unknown;\n}\n\nexport interface HttpResponseRaw {\n status: number;\n headers: Record<string, string>;\n json?: any;\n text?: string;\n}\n\nexport class HttpClient {\n constructor(private ctx: ExecuteContext) {}\n\n private resolveAuthHeader(): Record<string, string> {\n const { auth } = this.ctx;\n if (auth.oauth2?.accessToken) {\n return { Authorization: `Bearer ${auth.oauth2.accessToken}` };\n }\n if (auth.bearer?.token) {\n return { Authorization: `Bearer ${auth.bearer.token}` };\n }\n if (auth.apiKey?.value) {\n const headerName = auth.apiKey.name ?? \"X-API-Key\";\n return { [headerName]: auth.apiKey.value };\n }\n return {};\n }\n\n async request(options: HttpRequestOptions): Promise<HttpResponseRaw> {\n const fetchImpl = this.ctx.fetch ?? fetch;\n const url = new URL(options.path, this.ctx.baseUrl);\n\n if (options.query) {\n for (const [k, v] of Object.entries(options.query)) {\n if (v === undefined) continue;\n url.searchParams.set(k, String(v));\n }\n }\n\n const baseHeaders: Record<string, string> = {\n Accept: \"application/json\",\n ...(this.ctx.requestId ? { \"X-Request-Id\": this.ctx.requestId } : {}),\n ...this.resolveAuthHeader(),\n ...(options.headers ?? {})\n };\n\n const controller = new AbortController();\n const timeoutMs = this.ctx.timeoutMs ?? 15000;\n const t = setTimeout(() => controller.abort(), timeoutMs);\n\n const init: RequestInit = {\n method: options.method,\n headers: baseHeaders,\n signal: controller.signal\n };\n\n if (options.bodyJson !== undefined) {\n init.body = JSON.stringify(options.bodyJson);\n baseHeaders[\"Content-Type\"] = baseHeaders[\"Content-Type\"] ?? \"application/json\";\n }\n\n if (this.ctx.logDebug) {\n console.debug(\"[HttpClient] Request\", {\n url: url.toString(),\n method: options.method,\n headers: baseHeaders,\n body: options.bodyJson\n });\n }\n\n try {\n const res = await fetchImpl(url.toString(), init);\n const headersObj = Object.fromEntries(res.headers.entries());\n\n let json: any | undefined;\n let text: string | undefined;\n const contentType = res.headers.get(\"content-type\") || \"\";\n\n if (contentType.includes(\"application/json\")) {\n try {\n json = await res.json();\n } catch {\n json = undefined;\n }\n } else {\n try {\n text = await res.text();\n } catch {\n text = undefined;\n }\n }\n\n if (this.ctx.logDebug) {\n console.debug(\"[HttpClient] Response\", {\n status: res.status,\n headers: headersObj,\n json,\n text\n });\n }\n\n return {\n status: res.status,\n headers: headersObj,\n json,\n text\n };\n } finally {\n clearTimeout(t);\n }\n }\n}\n"]}
1
+ {"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../../../../src/templates/3rd-party-integration/src/http-client.ts"],"names":[],"mappings":"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","sourcesContent":["import { ExecuteContext } from \"./mcp-http-types\";\n\nexport interface HttpRequestOptions {\n method: string;\n path: string; // already resolved (including path params)\n query?: Record<string, string | number | boolean | undefined>;\n headers?: Record<string, string>;\n bodyJson?: unknown;\n}\n\nexport interface HttpResponseRaw {\n status: number;\n headers: Record<string, string>;\n json?: any;\n text?: string;\n}\n\nexport class HttpClient {\n constructor(private ctx: ExecuteContext) {}\n\n private resolveAuthHeader(): Record<string, string> {\n const { auth } = this.ctx;\n if (auth.oauth2?.accessToken) {\n return { Authorization: `Bearer ${auth.oauth2.accessToken}` };\n }\n if (auth.bearer?.token) {\n return { Authorization: `Bearer ${auth.bearer.token}` };\n }\n if (auth.apiKey?.value) {\n const headerName = auth.apiKey.name ?? \"X-API-Key\";\n return { [headerName]: auth.apiKey.value };\n }\n return {};\n }\n\n async request(options: HttpRequestOptions): Promise<HttpResponseRaw> {\n const fetchImpl = this.ctx.fetch ?? fetch;\n const url = new URL(options.path, this.ctx.baseUrl);\n\n if (options.query) {\n for (const [k, v] of Object.entries(options.query)) {\n if (v === undefined) continue;\n url.searchParams.set(k, String(v));\n }\n }\n\n const baseHeaders: Record<string, string> = {\n Accept: \"application/json\",\n ...(this.ctx.requestId ? { \"X-Request-Id\": this.ctx.requestId } : {}),\n ...this.resolveAuthHeader(),\n ...(options.headers ?? {})\n };\n\n const controller = new AbortController();\n const timeoutMs = this.ctx.timeoutMs ?? 15000;\n const t = setTimeout(() => controller.abort(), timeoutMs);\n\n const init: RequestInit = {\n method: options.method,\n headers: baseHeaders,\n signal: controller.signal\n };\n\n if (options.bodyJson !== undefined) {\n init.body = JSON.stringify(options.bodyJson);\n baseHeaders[\"Content-Type\"] = baseHeaders[\"Content-Type\"] ?? \"application/json\";\n }\n\n if (this.ctx.logDebug) {\n console.debug(\"[HttpClient] Request\", {\n url: url.toString(),\n method: options.method,\n headers: baseHeaders,\n body: options.bodyJson\n });\n }\n\n try {\n const res = await fetchImpl(url.toString(), init);\n const headersObj = Object.fromEntries(res.headers.entries());\n\n let json: any | undefined;\n let text: string | undefined;\n const contentType = res.headers.get(\"content-type\") || \"\";\n\n if (contentType.includes(\"application/json\")) {\n try {\n json = await res.json();\n } catch {\n json = undefined;\n }\n } else {\n try {\n text = await res.text();\n } catch {\n text = undefined;\n }\n }\n\n if (this.ctx.logDebug) {\n console.debug(\"[HttpClient] Response\", {\n status: res.status,\n headers: headersObj,\n json,\n text\n });\n }\n\n return {\n status: res.status,\n headers: headersObj,\n json,\n text\n };\n } finally {\n clearTimeout(t);\n }\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { z } from "zod";
1
+ import { z } from 'zod';
2
2
  /**
3
3
  * Shared output wrapper: all HTTP tools must return { status, headers, body }.
4
4
  */
@@ -8,15 +8,7 @@ export declare const makeHttpOutputSchema: <TBody extends z.ZodTypeAny>(bodySche
8
8
  status: z.ZodNumber;
9
9
  headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
10
10
  body: TBody;
11
- }, "strip", z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<{
12
- status: z.ZodNumber;
13
- headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
14
- body: TBody;
15
- }>, any> extends infer T ? { [k in keyof T]: T[k]; } : never, z.baseObjectInputType<{
16
- status: z.ZodNumber;
17
- headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
18
- body: TBody;
19
- }> extends infer T_1 ? { [k_1 in keyof T_1]: T_1[k_1]; } : never>;
11
+ }, z.core.$strip>;
20
12
  export type HttpOutput<TBody> = {
21
13
  status: number;
22
14
  headers?: Record<string, string>;
@@ -29,60 +21,16 @@ export declare const AuthContextSchema: z.ZodObject<{
29
21
  oauth2: z.ZodOptional<z.ZodObject<{
30
22
  accessToken: z.ZodString;
31
23
  idToken: z.ZodOptional<z.ZodString>;
32
- claims: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
33
- }, "strip", z.ZodTypeAny, {
34
- accessToken: string;
35
- idToken?: string | undefined;
36
- claims?: Record<string, any> | undefined;
37
- }, {
38
- accessToken: string;
39
- idToken?: string | undefined;
40
- claims?: Record<string, any> | undefined;
41
- }>>;
24
+ claims: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
25
+ }, z.core.$strip>>;
42
26
  bearer: z.ZodOptional<z.ZodObject<{
43
27
  token: z.ZodString;
44
- }, "strip", z.ZodTypeAny, {
45
- token: string;
46
- }, {
47
- token: string;
48
- }>>;
28
+ }, z.core.$strip>>;
49
29
  apiKey: z.ZodOptional<z.ZodObject<{
50
30
  name: z.ZodOptional<z.ZodString>;
51
31
  value: z.ZodString;
52
- }, "strip", z.ZodTypeAny, {
53
- value: string;
54
- name?: string | undefined;
55
- }, {
56
- value: string;
57
- name?: string | undefined;
58
- }>>;
59
- }, "strip", z.ZodTypeAny, {
60
- oauth2?: {
61
- accessToken: string;
62
- idToken?: string | undefined;
63
- claims?: Record<string, any> | undefined;
64
- } | undefined;
65
- bearer?: {
66
- token: string;
67
- } | undefined;
68
- apiKey?: {
69
- value: string;
70
- name?: string | undefined;
71
- } | undefined;
72
- }, {
73
- oauth2?: {
74
- accessToken: string;
75
- idToken?: string | undefined;
76
- claims?: Record<string, any> | undefined;
77
- } | undefined;
78
- bearer?: {
79
- token: string;
80
- } | undefined;
81
- apiKey?: {
82
- value: string;
83
- name?: string | undefined;
84
- } | undefined;
85
- }>;
32
+ }, z.core.$strip>>;
33
+ }, z.core.$strip>;
86
34
  export type AuthContext = z.infer<typeof AuthContextSchema>;
87
35
  export declare const ExecuteContextSchema: z.ZodObject<{
88
36
  baseUrl: z.ZodString;
@@ -90,105 +38,21 @@ export declare const ExecuteContextSchema: z.ZodObject<{
90
38
  oauth2: z.ZodOptional<z.ZodObject<{
91
39
  accessToken: z.ZodString;
92
40
  idToken: z.ZodOptional<z.ZodString>;
93
- claims: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
94
- }, "strip", z.ZodTypeAny, {
95
- accessToken: string;
96
- idToken?: string | undefined;
97
- claims?: Record<string, any> | undefined;
98
- }, {
99
- accessToken: string;
100
- idToken?: string | undefined;
101
- claims?: Record<string, any> | undefined;
102
- }>>;
41
+ claims: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
42
+ }, z.core.$strip>>;
103
43
  bearer: z.ZodOptional<z.ZodObject<{
104
44
  token: z.ZodString;
105
- }, "strip", z.ZodTypeAny, {
106
- token: string;
107
- }, {
108
- token: string;
109
- }>>;
45
+ }, z.core.$strip>>;
110
46
  apiKey: z.ZodOptional<z.ZodObject<{
111
47
  name: z.ZodOptional<z.ZodString>;
112
48
  value: z.ZodString;
113
- }, "strip", z.ZodTypeAny, {
114
- value: string;
115
- name?: string | undefined;
116
- }, {
117
- value: string;
118
- name?: string | undefined;
119
- }>>;
120
- }, "strip", z.ZodTypeAny, {
121
- oauth2?: {
122
- accessToken: string;
123
- idToken?: string | undefined;
124
- claims?: Record<string, any> | undefined;
125
- } | undefined;
126
- bearer?: {
127
- token: string;
128
- } | undefined;
129
- apiKey?: {
130
- value: string;
131
- name?: string | undefined;
132
- } | undefined;
133
- }, {
134
- oauth2?: {
135
- accessToken: string;
136
- idToken?: string | undefined;
137
- claims?: Record<string, any> | undefined;
138
- } | undefined;
139
- bearer?: {
140
- token: string;
141
- } | undefined;
142
- apiKey?: {
143
- value: string;
144
- name?: string | undefined;
145
- } | undefined;
146
- }>;
147
- fetch: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodString, z.ZodAny], z.ZodUnknown>, z.ZodPromise<z.ZodAny>>>;
49
+ }, z.core.$strip>>;
50
+ }, z.core.$strip>;
51
+ fetch: z.ZodOptional<z.ZodFunction<z.ZodTuple<[z.ZodString, z.ZodAny], null>, z.ZodPromise<z.ZodAny>>>;
148
52
  requestId: z.ZodOptional<z.ZodString>;
149
53
  timeoutMs: z.ZodOptional<z.ZodNumber>;
150
54
  logDebug: z.ZodOptional<z.ZodBoolean>;
151
- }, "strip", z.ZodTypeAny, {
152
- baseUrl: string;
153
- auth: {
154
- oauth2?: {
155
- accessToken: string;
156
- idToken?: string | undefined;
157
- claims?: Record<string, any> | undefined;
158
- } | undefined;
159
- bearer?: {
160
- token: string;
161
- } | undefined;
162
- apiKey?: {
163
- value: string;
164
- name?: string | undefined;
165
- } | undefined;
166
- };
167
- fetch?: ((args_0: string, args_1: any, ...args: unknown[]) => Promise<any>) | undefined;
168
- requestId?: string | undefined;
169
- timeoutMs?: number | undefined;
170
- logDebug?: boolean | undefined;
171
- }, {
172
- baseUrl: string;
173
- auth: {
174
- oauth2?: {
175
- accessToken: string;
176
- idToken?: string | undefined;
177
- claims?: Record<string, any> | undefined;
178
- } | undefined;
179
- bearer?: {
180
- token: string;
181
- } | undefined;
182
- apiKey?: {
183
- value: string;
184
- name?: string | undefined;
185
- } | undefined;
186
- };
187
- fetch?: ((args_0: string, args_1: any, ...args: unknown[]) => Promise<any>) | undefined;
188
- requestId?: string | undefined;
189
- timeoutMs?: number | undefined;
190
- logDebug?: boolean | undefined;
191
- }>;
55
+ }, z.core.$strip>;
192
56
  export type ExecuteContext = z.infer<typeof ExecuteContextSchema>;
193
57
  /**
194
58
  * Generic execute signature for TS tools.
@@ -6,11 +6,11 @@ const zod_1 = require("zod");
6
6
  * Shared output wrapper: all HTTP tools must return { status, headers, body }.
7
7
  */
8
8
  exports.HttpStatusSchema = zod_1.z.number().int().min(100).max(599);
9
- exports.HttpHeadersSchema = zod_1.z.record(zod_1.z.string());
9
+ exports.HttpHeadersSchema = zod_1.z.record(zod_1.z.string(), zod_1.z.string());
10
10
  const makeHttpOutputSchema = (bodySchema) => zod_1.z.object({
11
11
  status: exports.HttpStatusSchema,
12
12
  headers: exports.HttpHeadersSchema.optional(),
13
- body: bodySchema
13
+ body: bodySchema,
14
14
  });
15
15
  exports.makeHttpOutputSchema = makeHttpOutputSchema;
16
16
  /**
@@ -21,31 +21,32 @@ exports.AuthContextSchema = zod_1.z.object({
21
21
  .object({
22
22
  accessToken: zod_1.z.string(),
23
23
  idToken: zod_1.z.string().optional(),
24
- claims: zod_1.z.record(zod_1.z.any()).optional()
24
+ claims: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
25
25
  })
26
26
  .optional(),
27
27
  bearer: zod_1.z
28
28
  .object({
29
- token: zod_1.z.string()
29
+ token: zod_1.z.string(),
30
30
  })
31
31
  .optional(),
32
32
  apiKey: zod_1.z
33
33
  .object({
34
34
  name: zod_1.z.string().optional(),
35
- value: zod_1.z.string()
35
+ value: zod_1.z.string(),
36
36
  })
37
- .optional()
37
+ .optional(),
38
38
  });
39
39
  exports.ExecuteContextSchema = zod_1.z.object({
40
40
  baseUrl: zod_1.z.string().url(),
41
41
  auth: exports.AuthContextSchema,
42
42
  fetch: zod_1.z
43
- .function()
44
- .args(zod_1.z.string(), zod_1.z.any())
45
- .returns(zod_1.z.promise(zod_1.z.any()))
43
+ .function({
44
+ input: zod_1.z.tuple([zod_1.z.string(), zod_1.z.any()]),
45
+ output: zod_1.z.promise(zod_1.z.any()),
46
+ })
46
47
  .optional(),
47
48
  requestId: zod_1.z.string().optional(),
48
49
  timeoutMs: zod_1.z.number().int().positive().optional(),
49
- logDebug: zod_1.z.boolean().optional()
50
+ logDebug: zod_1.z.boolean().optional(),
50
51
  });
51
52
  //# sourceMappingURL=mcp-http-types.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-http-types.js","sourceRoot":"","sources":["../../../../../src/templates/3rd-party-integration/src/mcp-http-types.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAExB;;GAEG;AAEU,QAAA,gBAAgB,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACtD,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAE/C,MAAM,oBAAoB,GAAG,CAA6B,UAAiB,EAAE,EAAE,CACpF,OAAC,CAAC,MAAM,CAAC;IACP,MAAM,EAAE,wBAAgB;IACxB,OAAO,EAAE,yBAAiB,CAAC,QAAQ,EAAE;IACrC,IAAI,EAAE,UAAU;CACjB,CAAC,CAAC;AALQ,QAAA,oBAAoB,wBAK5B;AAQL;;GAEG;AAEU,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,MAAM,EAAE,OAAC;SACN,MAAM,CAAC;QACN,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE;QACvB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE;KACrC,CAAC;SACD,QAAQ,EAAE;IACb,MAAM,EAAE,OAAC;SACN,MAAM,CAAC;QACN,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;KAClB,CAAC;SACD,QAAQ,EAAE;IACb,MAAM,EAAE,OAAC;SACN,MAAM,CAAC;QACN,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC3B,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;KAClB,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAIU,QAAA,oBAAoB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3C,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACzB,IAAI,EAAE,yBAAiB;IACvB,KAAK,EAAE,OAAC;SACL,QAAQ,EAAE;SACV,IAAI,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,GAAG,EAAE,CAAC;SACzB,OAAO,CAAC,OAAC,CAAC,OAAO,CAAC,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC;SAC3B,QAAQ,EAAE;IACb,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACjD,QAAQ,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC","sourcesContent":["import { z } from \"zod\";\n\n/**\n * Shared output wrapper: all HTTP tools must return { status, headers, body }.\n */\n\nexport const HttpStatusSchema = z.number().int().min(100).max(599);\nexport const HttpHeadersSchema = z.record(z.string());\n\nexport const makeHttpOutputSchema = <TBody extends z.ZodTypeAny>(bodySchema: TBody) =>\n z.object({\n status: HttpStatusSchema,\n headers: HttpHeadersSchema.optional(),\n body: bodySchema\n });\n\nexport type HttpOutput<TBody> = {\n status: number;\n headers?: Record<string, string>;\n body: TBody;\n};\n\n/**\n * Shared auth/context types for TS tools.\n */\n\nexport const AuthContextSchema = z.object({\n oauth2: z\n .object({\n accessToken: z.string(),\n idToken: z.string().optional(),\n claims: z.record(z.any()).optional()\n })\n .optional(),\n bearer: z\n .object({\n token: z.string()\n })\n .optional(),\n apiKey: z\n .object({\n name: z.string().optional(),\n value: z.string()\n })\n .optional()\n});\n\nexport type AuthContext = z.infer<typeof AuthContextSchema>;\n\nexport const ExecuteContextSchema = z.object({\n baseUrl: z.string().url(),\n auth: AuthContextSchema,\n fetch: z\n .function()\n .args(z.string(), z.any())\n .returns(z.promise(z.any()))\n .optional(),\n requestId: z.string().optional(),\n timeoutMs: z.number().int().positive().optional(),\n logDebug: z.boolean().optional()\n});\n\nexport type ExecuteContext = z.infer<typeof ExecuteContextSchema>;\n\n/**\n * Generic execute signature for TS tools.\n */\n\nexport type ToolExecute<I, B> = (args: {\n input: I;\n ctx: ExecuteContext;\n}) => Promise<HttpOutput<B>>;\n"]}
1
+ {"version":3,"file":"mcp-http-types.js","sourceRoot":"","sources":["../../../../../src/templates/3rd-party-integration/src/mcp-http-types.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAExB;;GAEG;AAEU,QAAA,gBAAgB,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AACtD,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAE3D,MAAM,oBAAoB,GAAG,CAA6B,UAAiB,EAAE,EAAE,CACpF,OAAC,CAAC,MAAM,CAAC;IACP,MAAM,EAAE,wBAAgB;IACxB,OAAO,EAAE,yBAAiB,CAAC,QAAQ,EAAE;IACrC,IAAI,EAAE,UAAU;CACjB,CAAC,CAAC;AALQ,QAAA,oBAAoB,wBAK5B;AAQL;;GAEG;AAEU,QAAA,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACxC,MAAM,EAAE,OAAC;SACN,MAAM,CAAC;QACN,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE;QACvB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;KACrD,CAAC;SACD,QAAQ,EAAE;IACb,MAAM,EAAE,OAAC;SACN,MAAM,CAAC;QACN,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;KAClB,CAAC;SACD,QAAQ,EAAE;IACb,MAAM,EAAE,OAAC;SACN,MAAM,CAAC;QACN,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC3B,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;KAClB,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAIU,QAAA,oBAAoB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC3C,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACzB,IAAI,EAAE,yBAAiB;IACvB,KAAK,EAAE,OAAC;SACL,QAAQ,CAAC;QACR,KAAK,EAAE,OAAC,CAAC,KAAK,CAAC,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACrC,MAAM,EAAE,OAAC,CAAC,OAAO,CAAC,OAAC,CAAC,GAAG,EAAE,CAAC;KAC3B,CAAC;SACD,QAAQ,EAAE;IACb,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACjD,QAAQ,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC,CAAC","sourcesContent":["import { z } from 'zod';\n\n/**\n * Shared output wrapper: all HTTP tools must return { status, headers, body }.\n */\n\nexport const HttpStatusSchema = z.number().int().min(100).max(599);\nexport const HttpHeadersSchema = z.record(z.string(), z.string());\n\nexport const makeHttpOutputSchema = <TBody extends z.ZodTypeAny>(bodySchema: TBody) =>\n z.object({\n status: HttpStatusSchema,\n headers: HttpHeadersSchema.optional(),\n body: bodySchema,\n });\n\nexport type HttpOutput<TBody> = {\n status: number;\n headers?: Record<string, string>;\n body: TBody;\n};\n\n/**\n * Shared auth/context types for TS tools.\n */\n\nexport const AuthContextSchema = z.object({\n oauth2: z\n .object({\n accessToken: z.string(),\n idToken: z.string().optional(),\n claims: z.record(z.string(), z.unknown()).optional(),\n })\n .optional(),\n bearer: z\n .object({\n token: z.string(),\n })\n .optional(),\n apiKey: z\n .object({\n name: z.string().optional(),\n value: z.string(),\n })\n .optional(),\n});\n\nexport type AuthContext = z.infer<typeof AuthContextSchema>;\n\nexport const ExecuteContextSchema = z.object({\n baseUrl: z.string().url(),\n auth: AuthContextSchema,\n fetch: z\n .function({\n input: z.tuple([z.string(), z.any()]),\n output: z.promise(z.any()),\n })\n .optional(),\n requestId: z.string().optional(),\n timeoutMs: z.number().int().positive().optional(),\n logDebug: z.boolean().optional(),\n});\n\nexport type ExecuteContext = z.infer<typeof ExecuteContextSchema>;\n\n/**\n * Generic execute signature for TS tools.\n */\n\nexport type ToolExecute<I, B> = (args: { input: I; ctx: ExecuteContext }) => Promise<HttpOutput<B>>;\n"]}
@@ -3,57 +3,21 @@ import { HttpOutput, ToolExecute } from "../mcp-http-types";
3
3
  export declare const inputSchema: z.ZodObject<{
4
4
  limit: z.ZodOptional<z.ZodNumber>;
5
5
  query: z.ZodOptional<z.ZodString>;
6
- }, "strict", z.ZodTypeAny, {
7
- limit?: number | undefined;
8
- query?: string | undefined;
9
- }, {
10
- limit?: number | undefined;
11
- query?: string | undefined;
12
- }>;
6
+ }, z.core.$strict>;
13
7
  export type Input = z.infer<typeof inputSchema>;
14
8
  export declare const ItemSchema: z.ZodObject<{
15
9
  id: z.ZodString;
16
10
  name: z.ZodString;
17
11
  type: z.ZodString;
18
- }, "strict", z.ZodTypeAny, {
19
- name: string;
20
- type: string;
21
- id: string;
22
- }, {
23
- name: string;
24
- type: string;
25
- id: string;
26
- }>;
12
+ }, z.core.$strict>;
27
13
  export declare const BodySchema: z.ZodObject<{
28
14
  items: z.ZodArray<z.ZodObject<{
29
15
  id: z.ZodString;
30
16
  name: z.ZodString;
31
17
  type: z.ZodString;
32
- }, "strict", z.ZodTypeAny, {
33
- name: string;
34
- type: string;
35
- id: string;
36
- }, {
37
- name: string;
38
- type: string;
39
- id: string;
40
- }>, "many">;
18
+ }, z.core.$strict>>;
41
19
  nextCursor: z.ZodNullable<z.ZodString>;
42
- }, "strict", z.ZodTypeAny, {
43
- items: {
44
- name: string;
45
- type: string;
46
- id: string;
47
- }[];
48
- nextCursor: string | null;
49
- }, {
50
- items: {
51
- name: string;
52
- type: string;
53
- id: string;
54
- }[];
55
- nextCursor: string | null;
56
- }>;
20
+ }, z.core.$strict>;
57
21
  export type Body = z.infer<typeof BodySchema>;
58
22
  export declare const outputSchema: z.ZodObject<{
59
23
  status: z.ZodNumber;
@@ -63,54 +27,10 @@ export declare const outputSchema: z.ZodObject<{
63
27
  id: z.ZodString;
64
28
  name: z.ZodString;
65
29
  type: z.ZodString;
66
- }, "strict", z.ZodTypeAny, {
67
- name: string;
68
- type: string;
69
- id: string;
70
- }, {
71
- name: string;
72
- type: string;
73
- id: string;
74
- }>, "many">;
30
+ }, z.core.$strict>>;
75
31
  nextCursor: z.ZodNullable<z.ZodString>;
76
- }, "strict", z.ZodTypeAny, {
77
- items: {
78
- name: string;
79
- type: string;
80
- id: string;
81
- }[];
82
- nextCursor: string | null;
83
- }, {
84
- items: {
85
- name: string;
86
- type: string;
87
- id: string;
88
- }[];
89
- nextCursor: string | null;
90
- }>;
91
- }, "strip", z.ZodTypeAny, {
92
- status: number;
93
- body: {
94
- items: {
95
- name: string;
96
- type: string;
97
- id: string;
98
- }[];
99
- nextCursor: string | null;
100
- };
101
- headers?: Record<string, string> | undefined;
102
- }, {
103
- status: number;
104
- body: {
105
- items: {
106
- name: string;
107
- type: string;
108
- id: string;
109
- }[];
110
- nextCursor: string | null;
111
- };
112
- headers?: Record<string, string> | undefined;
113
- }>;
32
+ }, z.core.$strict>;
33
+ }, z.core.$strip>;
114
34
  export type Output = HttpOutput<Body>;
115
35
  /**
116
36
  * Example tool: "example.list"