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 +30 -18
- package/package.json +7 -6
- package/src/args.d.ts +5 -1
- package/src/args.js +10 -0
- package/src/args.js.map +1 -1
- package/src/cli.js +12 -0
- package/src/cli.js.map +1 -1
- package/src/commands/create.js +79 -5
- package/src/commands/create.js.map +1 -1
- package/src/commands/test.d.ts +12 -0
- package/src/commands/test.js +183 -0
- package/src/commands/test.js.map +1 -0
- package/src/templates/3rd-party-integration/src/http-client.js +1 -0
- package/src/templates/3rd-party-integration/src/http-client.js.map +1 -1
- package/src/templates/3rd-party-integration/src/mcp-http-types.d.ts +14 -150
- package/src/templates/3rd-party-integration/src/mcp-http-types.js +11 -10
- package/src/templates/3rd-party-integration/src/mcp-http-types.js.map +1 -1
- package/src/templates/3rd-party-integration/src/tools/example.list.d.ts +7 -87
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
|
-
**
|
|
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@^
|
|
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({...})
|
|
299
|
-
minimal
|
|
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
|
-
|
|
304
|
-
|
|
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
|
-
|
|
309
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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/
|
|
446
|
-
[11]: https://docs.agentfront.dev/docs/
|
|
447
|
-
[12]: https://docs.agentfront.dev/docs/
|
|
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.
|
|
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": "
|
|
29
|
-
"@frontmcp/plugins": "
|
|
30
|
-
"@frontmcp/adapters": "
|
|
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": "^
|
|
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":";;
|
|
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;
|
|
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"]}
|
package/src/commands/create.js
CHANGED
|
@@ -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 =
|
|
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': '^
|
|
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
|
|
201
|
-
console.log(' 4) npm run inspect
|
|
202
|
-
console.log(' 5) npm run 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"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../../../../src/templates/3rd-party-integration/src/http-client.ts"],"names":[],"mappings":";;;AAiBA,MAAa,UAAU;
|
|
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
|
|
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
|
-
},
|
|
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.
|
|
33
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
53
|
-
|
|
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.
|
|
94
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
114
|
-
|
|
115
|
-
|
|
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
|
-
},
|
|
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.
|
|
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
|
-
.
|
|
45
|
-
|
|
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;
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
77
|
-
|
|
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"
|