@belgie/mcp 0.1.0 → 0.32.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/dist/index.js +16 -231
- package/dist/index.js.map +1 -1
- package/dist/vite.js +13 -13
- package/dist/vite.js.map +1 -1
- package/package.json +19 -43
- package/types/html.d.ts +10 -0
- package/types/index.d.ts +29 -0
- package/types/scan-widgets.d.ts +15 -0
- package/types/validate-widget.d.ts +1 -0
- package/types/vite.d.ts +5 -0
- package/README.md +0 -98
- package/dist/cli.d.ts +0 -10
- package/dist/cli.js +0 -119
- package/dist/cli.js.map +0 -1
- package/dist/codegen-DnMS1wg_.js +0 -688
- package/dist/codegen-DnMS1wg_.js.map +0 -1
- package/dist/codegen.d.ts +0 -11
- package/dist/codegen.js +0 -2
- package/dist/index.d.ts +0 -60
- package/dist/internal.d.ts +0 -12
- package/dist/internal.js +0 -37
- package/dist/internal.js.map +0 -1
- package/dist/tool-result-source-DTFIKHfH.js +0 -99
- package/dist/tool-result-source-DTFIKHfH.js.map +0 -1
- package/dist/tool-result-source-niHoRYxM.d.ts +0 -42
- package/dist/vite.d.ts +0 -9
package/package.json
CHANGED
|
@@ -1,74 +1,50 @@
|
|
|
1
1
|
{
|
|
2
|
-
"author": "Matt LeMay <mplemay@users.noreply.github.com>",
|
|
3
|
-
"bin": {
|
|
4
|
-
"belgie-mcp": "./dist/cli.js"
|
|
5
|
-
},
|
|
6
|
-
"bugs": {
|
|
7
|
-
"url": "https://github.com/mplemay/belgie/issues"
|
|
8
|
-
},
|
|
9
2
|
"dependencies": {
|
|
10
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
11
|
-
"open": "^11.0.0",
|
|
12
3
|
"react": "19.2.6",
|
|
13
|
-
"react-dom": "19.2.6"
|
|
14
|
-
"zod": "^4.4.3"
|
|
4
|
+
"react-dom": "19.2.6"
|
|
15
5
|
},
|
|
16
|
-
"description": "TypeScript support for Belgie MCP widgets and generated tool clients.",
|
|
17
6
|
"devDependencies": {
|
|
18
|
-
"@arethetypeswrong/core": "^0.18.5",
|
|
19
7
|
"@modelcontextprotocol/ext-apps": "^1.7.4",
|
|
20
8
|
"@types/node": "25.9.1",
|
|
21
9
|
"@types/react": "19.2.15",
|
|
22
10
|
"@types/react-dom": "19.2.3",
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"publint": "^0.3.21",
|
|
26
|
-
"tsdown": "^0.22.11",
|
|
27
|
-
"typescript": "^7.0.2",
|
|
28
|
-
"vite": "8.1.3",
|
|
29
|
-
"vitest": "^4.1.10"
|
|
11
|
+
"typescript": "~6.0.3",
|
|
12
|
+
"vite": "8.1.3"
|
|
30
13
|
},
|
|
31
14
|
"engines": {
|
|
32
15
|
"node": ">=22"
|
|
33
16
|
},
|
|
34
17
|
"exports": {
|
|
35
|
-
".":
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"./
|
|
18
|
+
".": {
|
|
19
|
+
"import": "./dist/index.js",
|
|
20
|
+
"types": "./types/index.d.ts"
|
|
21
|
+
},
|
|
22
|
+
"./vite": {
|
|
23
|
+
"import": "./dist/vite.js",
|
|
24
|
+
"types": "./types/vite.d.ts"
|
|
25
|
+
}
|
|
40
26
|
},
|
|
41
27
|
"files": [
|
|
42
|
-
"dist"
|
|
28
|
+
"dist",
|
|
29
|
+
"types"
|
|
43
30
|
],
|
|
44
|
-
"
|
|
45
|
-
"license": "MIT",
|
|
46
|
-
"main": "./dist/index.js",
|
|
47
|
-
"module": "./dist/index.js",
|
|
31
|
+
"main": "dist/index.js",
|
|
48
32
|
"name": "@belgie/mcp",
|
|
49
33
|
"peerDependencies": {
|
|
50
34
|
"@modelcontextprotocol/ext-apps": ">=1.0.0",
|
|
51
35
|
"vite": ">=8"
|
|
52
36
|
},
|
|
53
37
|
"private": false,
|
|
54
|
-
"publishConfig": {
|
|
55
|
-
"access": "public"
|
|
56
|
-
},
|
|
57
38
|
"repository": {
|
|
58
39
|
"directory": "packages/mcp",
|
|
59
40
|
"type": "git",
|
|
60
|
-
"url": "
|
|
41
|
+
"url": "https://github.com/mplemay/belgie"
|
|
61
42
|
},
|
|
62
43
|
"scripts": {
|
|
63
|
-
"build": "
|
|
64
|
-
"
|
|
65
|
-
"dev": "tsdown --watch",
|
|
66
|
-
"prepublishOnly": "npm test",
|
|
67
|
-
"test": "npm run build && npm run test:coverage && npm run check",
|
|
68
|
-
"test:coverage": "vitest run --coverage",
|
|
69
|
-
"test:watch": "vitest"
|
|
44
|
+
"build": "vite build && node ./node_modules/typescript/bin/tsc",
|
|
45
|
+
"clean": "rm -rf dist types"
|
|
70
46
|
},
|
|
71
47
|
"type": "module",
|
|
72
|
-
"types": "
|
|
73
|
-
"version": "0.
|
|
48
|
+
"types": "types/index.d.ts",
|
|
49
|
+
"version": "0.32.0"
|
|
74
50
|
}
|
package/types/html.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type WidgetHtmlDocumentOptions = {
|
|
2
|
+
inlineScript?: string;
|
|
3
|
+
inlineStyles?: string[];
|
|
4
|
+
scripts?: string[];
|
|
5
|
+
styles?: string[];
|
|
6
|
+
};
|
|
7
|
+
export declare function escapeInlineScript(value: string): string;
|
|
8
|
+
export declare function escapeInlineStyle(value: string): string;
|
|
9
|
+
export declare function buildVirtualEntry(widgetFilePath: string): string;
|
|
10
|
+
export declare function renderWidgetHtmlDocument(options: WidgetHtmlDocumentOptions): string;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type ComponentType, type ReactNode } from "react";
|
|
2
|
+
import { App, type AppEventMap, type AppOptions, type McpUiAppCapabilities } from "@modelcontextprotocol/ext-apps";
|
|
3
|
+
export type WidgetMetadata = {
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
title?: string;
|
|
7
|
+
capabilities?: McpUiAppCapabilities;
|
|
8
|
+
} & Pick<AppOptions, "autoResize" | "strict">;
|
|
9
|
+
export type WidgetHooks = {
|
|
10
|
+
before?: () => void | Promise<void>;
|
|
11
|
+
after?: () => void | Promise<void>;
|
|
12
|
+
error?: (error: Error) => void;
|
|
13
|
+
toolInput?: (params: AppEventMap["toolinput"]) => void;
|
|
14
|
+
toolInputPartial?: (params: AppEventMap["toolinputpartial"]) => void;
|
|
15
|
+
toolResult?: (params: AppEventMap["toolresult"]) => void;
|
|
16
|
+
toolCancelled?: (params: AppEventMap["toolcancelled"]) => void;
|
|
17
|
+
hostContextChanged?: (params: AppEventMap["hostcontextchanged"]) => void;
|
|
18
|
+
teardown?: NonNullable<App["onteardown"]>;
|
|
19
|
+
};
|
|
20
|
+
export type WidgetProps = {
|
|
21
|
+
metadata: WidgetMetadata;
|
|
22
|
+
children: ReactNode;
|
|
23
|
+
hooks?: WidgetHooks;
|
|
24
|
+
fallback?: ReactNode;
|
|
25
|
+
error?: ReactNode | ((error: Error) => ReactNode);
|
|
26
|
+
};
|
|
27
|
+
export declare function useWidget(): App;
|
|
28
|
+
export declare function Widget({ metadata, children, hooks, fallback, error: errorUI, }: WidgetProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | import("react/jsx-runtime").JSX.Element | null | undefined;
|
|
29
|
+
export declare function mountWidget(Widget: ComponentType): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type WidgetCandidate = {
|
|
2
|
+
name: string;
|
|
3
|
+
filePath: string;
|
|
4
|
+
};
|
|
5
|
+
export type InvalidWidget = {
|
|
6
|
+
filePath: string;
|
|
7
|
+
};
|
|
8
|
+
export type WidgetScanResult = {
|
|
9
|
+
valid: WidgetCandidate[];
|
|
10
|
+
invalid: InvalidWidget[];
|
|
11
|
+
};
|
|
12
|
+
export declare function scanWidgetsSync(srcDir: string): WidgetScanResult;
|
|
13
|
+
export declare function assertUniqueWidgetNames(widgets: WidgetCandidate[]): void;
|
|
14
|
+
export declare function assertNoInvalidWidgets(invalid: InvalidWidget[]): void;
|
|
15
|
+
export declare function discoverWidgetsSync(srcDir: string): WidgetCandidate[];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function hasDefaultExport(code: string): boolean;
|
package/types/vite.d.ts
ADDED
package/README.md
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
# `@belgie/mcp`
|
|
2
|
-
|
|
3
|
-
TypeScript helpers for building Belgie MCP Apps, generating typed MCP tool callers, and packaging path-based React
|
|
4
|
-
widgets with Vite.
|
|
5
|
-
|
|
6
|
-
## Installation
|
|
7
|
-
|
|
8
|
-
Install the package and its MCP Apps peer dependency with npm:
|
|
9
|
-
|
|
10
|
-
```sh
|
|
11
|
-
npm install @belgie/mcp @modelcontextprotocol/ext-apps
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Install Vite when using the widget plugin:
|
|
15
|
-
|
|
16
|
-
```sh
|
|
17
|
-
npm install --save-dev vite
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Package exports
|
|
21
|
-
|
|
22
|
-
- `@belgie/mcp` exports `Widget`, `mountWidget`, `useWidget`, `useToolResult`, context-bound App helpers, and MCP tool
|
|
23
|
-
errors.
|
|
24
|
-
- `@belgie/mcp/codegen` exports programmatic MCP tool-type generation.
|
|
25
|
-
- `@belgie/mcp/internal` contains the runtime factories used by generated callers.
|
|
26
|
-
- `@belgie/mcp/vite` exports the `belgie()` Vite plugin.
|
|
27
|
-
- `@belgie/mcp/package.json` exposes the package metadata.
|
|
28
|
-
|
|
29
|
-
The package is ESM-only and requires Node.js 22 or newer.
|
|
30
|
-
|
|
31
|
-
## Generate typed tool callers
|
|
32
|
-
|
|
33
|
-
Run the CLI against a streamable HTTP MCP endpoint:
|
|
34
|
-
|
|
35
|
-
```sh
|
|
36
|
-
npx belgie-mcp generate https://example.com/mcp --output src/mcp-tools.ts
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
OAuth is enabled by default. Use `--no-oauth` for an endpoint that does not require it, `--no-open` to print the
|
|
40
|
-
authorization URL, `--header NAME:VALUE` for a direct header, or `--header-env NAME=ENV_VAR` to read a secret from the
|
|
41
|
-
environment. `--check` verifies that an existing output file is current without rewriting it.
|
|
42
|
-
|
|
43
|
-
Generated callers execute only when called, use the connected widget App by default, and accept an explicit App as the
|
|
44
|
-
optional second argument:
|
|
45
|
-
|
|
46
|
-
```ts
|
|
47
|
-
import { getWeather } from "./mcp-tools.ts";
|
|
48
|
-
|
|
49
|
-
const { result, error } = await getWeather({ city: "Austin" });
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## Build a widget
|
|
53
|
-
|
|
54
|
-
Widgets are discovered at `<srcDir>/<name>/widget.tsx` and must have a default export:
|
|
55
|
-
|
|
56
|
-
```tsx
|
|
57
|
-
import { Widget, mountWidget, useToolResult } from "@belgie/mcp";
|
|
58
|
-
import { getWeather } from "../../../mcp-tools.ts";
|
|
59
|
-
|
|
60
|
-
function Weather() {
|
|
61
|
-
const weather = useToolResult(getWeather);
|
|
62
|
-
return (
|
|
63
|
-
<Widget metadata={{ name: "weather", version: "1.0.0" }}>
|
|
64
|
-
{weather.data?.summary ?? "Waiting for weather"}
|
|
65
|
-
</Widget>
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
mountWidget(Weather);
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Add the plugin to a normal Vite configuration. Development serves each widget at `/widgets/<name>/index.html`;
|
|
73
|
-
production emits a self-contained `dist/widgets/<name>/index.html` with JavaScript, CSS, and assets inlined.
|
|
74
|
-
|
|
75
|
-
```ts
|
|
76
|
-
import { defineConfig } from "vite";
|
|
77
|
-
import { belgie } from "@belgie/mcp/vite";
|
|
78
|
-
|
|
79
|
-
export default defineConfig({
|
|
80
|
-
plugins: [belgie({ srcDir: "src/widgets" })],
|
|
81
|
-
});
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## Development
|
|
85
|
-
|
|
86
|
-
This package uses npm and keeps its lockfile in version control:
|
|
87
|
-
|
|
88
|
-
```sh
|
|
89
|
-
npm ci
|
|
90
|
-
npm run dev
|
|
91
|
-
npm run check
|
|
92
|
-
npm run test:watch
|
|
93
|
-
npm test
|
|
94
|
-
npm pack --dry-run
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
`npm test` builds with tsdown, validates the package with publint and `@arethetypeswrong/cli` rules, runs the serialized
|
|
98
|
-
Vitest suite with V8 coverage, and checks TypeScript 7 declarations and API fixtures.
|
package/dist/cli.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
//#region src/cli.d.ts
|
|
2
|
-
declare function values(value: string | string[] | undefined): string[];
|
|
3
|
-
declare function parseHeader(value: string): [string, string];
|
|
4
|
-
declare function parseEnvironmentHeader(value: string): [string, string];
|
|
5
|
-
declare function runCli(args?: string[]): Promise<void>;
|
|
6
|
-
declare function isDirectExecution(moduleUrl: string, executable: string | undefined): boolean;
|
|
7
|
-
declare function reportCliError(cause: unknown): void;
|
|
8
|
-
//#endregion
|
|
9
|
-
export { isDirectExecution, parseEnvironmentHeader, parseHeader, reportCliError, runCli, values };
|
|
10
|
-
//# sourceMappingURL=cli.d.ts.map
|
package/dist/cli.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { t as generateToolTypes } from "./codegen-DnMS1wg_.js";
|
|
3
|
-
import { realpathSync } from "node:fs";
|
|
4
|
-
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
|
-
import { dirname, resolve } from "node:path";
|
|
6
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
-
import { parseArgs } from "node:util";
|
|
8
|
-
//#region src/cli.ts
|
|
9
|
-
const USAGE = `Usage:
|
|
10
|
-
belgie-mcp generate <url> --output <file> [options]
|
|
11
|
-
|
|
12
|
-
Options:
|
|
13
|
-
--check Fail when the output file is missing or stale
|
|
14
|
-
--header NAME:VALUE Add an introspection header (repeatable)
|
|
15
|
-
--header-env NAME=ENV_VAR Read a header value from the environment (repeatable)
|
|
16
|
-
--no-oauth Disable automatic OAuth discovery and PKCE
|
|
17
|
-
--no-open Print the OAuth URL instead of opening a browser
|
|
18
|
-
`;
|
|
19
|
-
function values(value) {
|
|
20
|
-
if (value === void 0) return [];
|
|
21
|
-
return Array.isArray(value) ? value : [value];
|
|
22
|
-
}
|
|
23
|
-
function parseHeader(value) {
|
|
24
|
-
const separator = value.indexOf(":");
|
|
25
|
-
if (separator <= 0) throw new Error(`Invalid --header ${JSON.stringify(value)}; expected NAME:VALUE`);
|
|
26
|
-
const name = value.slice(0, separator).trim();
|
|
27
|
-
const headerValue = value.slice(separator + 1).trim();
|
|
28
|
-
if (name.length === 0 || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u.test(name)) throw new Error(`Invalid header name ${JSON.stringify(name)}`);
|
|
29
|
-
return [name, headerValue];
|
|
30
|
-
}
|
|
31
|
-
function parseEnvironmentHeader(value) {
|
|
32
|
-
const separator = value.indexOf("=");
|
|
33
|
-
if (separator <= 0 || separator === value.length - 1) throw new Error(`Invalid --header-env ${JSON.stringify(value)}; expected NAME=ENV_VAR`);
|
|
34
|
-
const name = value.slice(0, separator).trim();
|
|
35
|
-
const environmentName = value.slice(separator + 1).trim();
|
|
36
|
-
if (name.length === 0 || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u.test(name)) throw new Error(`Invalid header name ${JSON.stringify(name)}`);
|
|
37
|
-
if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(environmentName)) throw new Error(`Invalid environment variable name ${JSON.stringify(environmentName)}`);
|
|
38
|
-
const headerValue = process.env[environmentName];
|
|
39
|
-
if (headerValue === void 0) throw new Error(`Environment variable ${environmentName} is not set`);
|
|
40
|
-
return [name, headerValue];
|
|
41
|
-
}
|
|
42
|
-
async function runCli(args = process.argv.slice(2)) {
|
|
43
|
-
const { positionals, values: options } = parseArgs({
|
|
44
|
-
args,
|
|
45
|
-
allowPositionals: true,
|
|
46
|
-
options: {
|
|
47
|
-
check: {
|
|
48
|
-
type: "boolean",
|
|
49
|
-
default: false
|
|
50
|
-
},
|
|
51
|
-
header: {
|
|
52
|
-
type: "string",
|
|
53
|
-
multiple: true
|
|
54
|
-
},
|
|
55
|
-
"header-env": {
|
|
56
|
-
type: "string",
|
|
57
|
-
multiple: true
|
|
58
|
-
},
|
|
59
|
-
"no-oauth": {
|
|
60
|
-
type: "boolean",
|
|
61
|
-
default: false
|
|
62
|
-
},
|
|
63
|
-
"no-open": {
|
|
64
|
-
type: "boolean",
|
|
65
|
-
default: false
|
|
66
|
-
},
|
|
67
|
-
output: {
|
|
68
|
-
type: "string",
|
|
69
|
-
short: "o"
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
strict: true
|
|
73
|
-
});
|
|
74
|
-
if (positionals[0] !== "generate" || positionals.length !== 2) throw new Error(USAGE);
|
|
75
|
-
if (options.output === void 0) throw new Error(`--output is required\n\n${USAGE}`);
|
|
76
|
-
const headers = Object.fromEntries([...values(options.header).map(parseHeader), ...values(options["header-env"]).map(parseEnvironmentHeader)]);
|
|
77
|
-
const output = resolve(options.output);
|
|
78
|
-
const generated = await generateToolTypes({
|
|
79
|
-
url: positionals[1],
|
|
80
|
-
headers,
|
|
81
|
-
oauth: !options["no-oauth"],
|
|
82
|
-
openBrowser: !options["no-open"]
|
|
83
|
-
});
|
|
84
|
-
if (options.check) {
|
|
85
|
-
let current;
|
|
86
|
-
try {
|
|
87
|
-
current = await readFile(output, "utf8");
|
|
88
|
-
} catch (cause) {
|
|
89
|
-
if (!(cause instanceof Error && "code" in cause && cause.code === "ENOENT")) throw cause;
|
|
90
|
-
}
|
|
91
|
-
if (current !== generated) throw new Error(`Generated MCP tool types are stale or missing: ${output}`);
|
|
92
|
-
process.stdout.write(`MCP tool types are current: ${output}\n`);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
await mkdir(dirname(output), { recursive: true });
|
|
96
|
-
await writeFile(output, generated, "utf8");
|
|
97
|
-
process.stdout.write(`Generated MCP tool types: ${output}\n`);
|
|
98
|
-
}
|
|
99
|
-
function isDirectExecution(moduleUrl, executable) {
|
|
100
|
-
if (executable === void 0) return false;
|
|
101
|
-
const executionPath = (value) => {
|
|
102
|
-
try {
|
|
103
|
-
return realpathSync(value);
|
|
104
|
-
} catch {
|
|
105
|
-
return resolve(value);
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
return executionPath(executable) === executionPath(fileURLToPath(moduleUrl));
|
|
109
|
-
}
|
|
110
|
-
function reportCliError(cause) {
|
|
111
|
-
const message = cause instanceof Error ? cause.message : String(cause);
|
|
112
|
-
process.stderr.write(`${message}\n`);
|
|
113
|
-
process.exitCode = 1;
|
|
114
|
-
}
|
|
115
|
-
if (isDirectExecution(import.meta.url, process.argv[1])) runCli().catch(reportCliError);
|
|
116
|
-
//#endregion
|
|
117
|
-
export { isDirectExecution, parseEnvironmentHeader, parseHeader, reportCliError, runCli, values };
|
|
118
|
-
|
|
119
|
-
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { realpathSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { parseArgs } from \"node:util\";\n\nimport { generateToolTypes } from \"./codegen\";\n\nconst USAGE = `Usage:\n belgie-mcp generate <url> --output <file> [options]\n\nOptions:\n --check Fail when the output file is missing or stale\n --header NAME:VALUE Add an introspection header (repeatable)\n --header-env NAME=ENV_VAR Read a header value from the environment (repeatable)\n --no-oauth Disable automatic OAuth discovery and PKCE\n --no-open Print the OAuth URL instead of opening a browser\n`;\n\nexport function values(value: string | string[] | undefined): string[] {\n if (value === undefined) {\n return [];\n }\n return Array.isArray(value) ? value : [value];\n}\n\nexport function parseHeader(value: string): [string, string] {\n const separator = value.indexOf(\":\");\n if (separator <= 0) {\n throw new Error(`Invalid --header ${JSON.stringify(value)}; expected NAME:VALUE`);\n }\n const name = value.slice(0, separator).trim();\n const headerValue = value.slice(separator + 1).trim();\n if (name.length === 0 || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u.test(name)) {\n throw new Error(`Invalid header name ${JSON.stringify(name)}`);\n }\n return [name, headerValue];\n}\n\nexport function parseEnvironmentHeader(value: string): [string, string] {\n const separator = value.indexOf(\"=\");\n if (separator <= 0 || separator === value.length - 1) {\n throw new Error(\n `Invalid --header-env ${JSON.stringify(value)}; expected NAME=ENV_VAR`,\n );\n }\n const name = value.slice(0, separator).trim();\n const environmentName = value.slice(separator + 1).trim();\n if (name.length === 0 || !/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/u.test(name)) {\n throw new Error(`Invalid header name ${JSON.stringify(name)}`);\n }\n if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(environmentName)) {\n throw new Error(`Invalid environment variable name ${JSON.stringify(environmentName)}`);\n }\n const headerValue = process.env[environmentName];\n if (headerValue === undefined) {\n throw new Error(`Environment variable ${environmentName} is not set`);\n }\n return [name, headerValue];\n}\n\nexport async function runCli(args: string[] = process.argv.slice(2)): Promise<void> {\n const { positionals, values: options } = parseArgs({\n args,\n allowPositionals: true,\n options: {\n check: { type: \"boolean\", default: false },\n header: { type: \"string\", multiple: true },\n \"header-env\": { type: \"string\", multiple: true },\n \"no-oauth\": { type: \"boolean\", default: false },\n \"no-open\": { type: \"boolean\", default: false },\n output: { type: \"string\", short: \"o\" },\n },\n strict: true,\n });\n\n if (positionals[0] !== \"generate\" || positionals.length !== 2) {\n throw new Error(USAGE);\n }\n if (options.output === undefined) {\n throw new Error(`--output is required\\n\\n${USAGE}`);\n }\n\n const headers = Object.fromEntries([\n ...values(options.header).map(parseHeader),\n ...values(options[\"header-env\"]).map(parseEnvironmentHeader),\n ]);\n const output = resolve(options.output);\n const generated = await generateToolTypes({\n url: positionals[1]!,\n headers,\n oauth: !options[\"no-oauth\"],\n openBrowser: !options[\"no-open\"],\n });\n\n if (options.check) {\n let current: string | undefined;\n try {\n current = await readFile(output, \"utf8\");\n } catch (cause: unknown) {\n if (!(cause instanceof Error && \"code\" in cause && cause.code === \"ENOENT\")) {\n throw cause;\n }\n }\n if (current !== generated) {\n throw new Error(`Generated MCP tool types are stale or missing: ${output}`);\n }\n process.stdout.write(`MCP tool types are current: ${output}\\n`);\n return;\n }\n\n await mkdir(dirname(output), { recursive: true });\n await writeFile(output, generated, \"utf8\");\n process.stdout.write(`Generated MCP tool types: ${output}\\n`);\n}\n\nexport function isDirectExecution(moduleUrl: string, executable: string | undefined): boolean {\n if (executable === undefined) {\n return false;\n }\n const executionPath = (value: string) => {\n try {\n return realpathSync(value);\n } catch {\n return resolve(value);\n }\n };\n return executionPath(executable) === executionPath(fileURLToPath(moduleUrl));\n}\n\nexport function reportCliError(cause: unknown): void {\n const message = cause instanceof Error ? cause.message : String(cause);\n process.stderr.write(`${message}\\n`);\n process.exitCode = 1;\n}\n\nif (isDirectExecution(import.meta.url, process.argv[1])) {\n runCli().catch(reportCliError);\n}\n"],"mappings":"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"}
|