@miragon/mcp-toolkit-tool-codegen 0.10.1

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 ADDED
@@ -0,0 +1,41 @@
1
+ # @miragon/mcp-toolkit-tool-codegen
2
+
3
+ Build-time codegen + runtime glue for type-safe MCP tool calls: TypedCallTool
4
+ helper and a CLI that generates TypeScript types + React Query hooks from an
5
+ MCP server's tools/list.
6
+
7
+ ## Install
8
+
9
+ Published to the public npm registry under the `@miragon` scope — no `.npmrc`
10
+ or token needed.
11
+
12
+ ```sh
13
+ pnpm add -D @miragon/mcp-toolkit-tool-codegen @miragon/mcp-toolkit-core @modelcontextprotocol/sdk@1.29.0
14
+ ```
15
+
16
+ ## Import paths
17
+
18
+ | Subpath | Key exports | Constraint |
19
+ | ----------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- |
20
+ | `@miragon/mcp-toolkit-tool-codegen` | `generateTools`, `renderCodegen`, `writeCodegenOutput`, `fetchUpstreamTools` | Build-time only — never import from runtime code. |
21
+ | `…-tool-codegen/runtime` | `ToolShape`, `TypedCallTool` (types only) | The only subpath widget bundles / step modules may import; pulls in no `handlebars` / codegen deps. |
22
+ | `…-tool-codegen/templates/*` | Handlebars templates used by the codegen | Internal to the CLI. |
23
+
24
+ ## CLI
25
+
26
+ The `mcp-tool-codegen` bin generates `tools.ts` + `hooks.tsx` from a
27
+ source server's `tools/list`:
28
+
29
+ ```sh
30
+ mcp-tool-codegen generate # reads ./codegen.config.ts (CodegenConfig)
31
+ mcp-tool-codegen generate --check # CI: exit 1 on drift vs committed output
32
+ mcp-tool-codegen inspect --upstream https://source.example/mcp
33
+ ```
34
+
35
+ Generated code imports only `@miragon/mcp-toolkit-tool-codegen/runtime`.
36
+
37
+ ## Links
38
+
39
+ - [API reference](https://github.com/Miragon/mcp-toolkit/blob/main/docs/reference/api-tool-codegen.md)
40
+ - [Getting started](https://github.com/Miragon/mcp-toolkit/blob/main/docs/getting-started.md)
41
+ - [Starter template](https://github.com/Miragon/mcp-toolkit-starter) — "Use this template" for a new server project
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable no-console */
3
+ import fs from "node:fs/promises";
4
+ import os from "node:os";
5
+ import path from "node:path";
6
+ import { pathToFileURL } from "node:url";
7
+ import { generateTools, writeCodegenOutput } from "./codegen.js";
8
+ import { fetchUpstreamTools } from "./fetch-tools.js";
9
+ function parseArgs(argv) {
10
+ const args = { command: "help", check: false };
11
+ const [command, ...rest] = argv;
12
+ if (command === "generate" || command === "inspect")
13
+ args.command = command;
14
+ for (let i = 0; i < rest.length; i++) {
15
+ const arg = rest[i];
16
+ const next = () => rest[++i];
17
+ switch (arg) {
18
+ case "--config":
19
+ case "-c":
20
+ args.config = next();
21
+ break;
22
+ case "--check":
23
+ args.check = true;
24
+ break;
25
+ case "--upstream":
26
+ case "-u":
27
+ args.upstream = next();
28
+ break;
29
+ case "--token":
30
+ args.token = next();
31
+ break;
32
+ case "--header":
33
+ args.header = next();
34
+ break;
35
+ case "--header-value":
36
+ args.headerValue = next();
37
+ break;
38
+ case "--out":
39
+ case "-o":
40
+ args.out = next();
41
+ break;
42
+ case "--proxy":
43
+ case "-p":
44
+ args.proxyName = next();
45
+ break;
46
+ case "--help":
47
+ case "-h":
48
+ args.command = "help";
49
+ break;
50
+ }
51
+ }
52
+ return args;
53
+ }
54
+ function printHelp() {
55
+ console.log(`mcp-tool-codegen — generate typed TS client code from an MCP server's tools/list.
56
+
57
+ Commands:
58
+ generate [--config <path>] [--check]
59
+ Fetch tools/list and write TypeScript + React Query hooks.
60
+ --check regenerate into a temp dir and exit != 0 if the output differs
61
+ from the committed files (for CI drift checks)
62
+ inspect --upstream <url> [--token <bearer>] [--header <name> --header-value <v>]
63
+ Print a markdown table of the upstream's tools without generating code.
64
+ help
65
+ Show this message.
66
+
67
+ Generate reads its configuration from a file (default: ./codegen.config.ts).
68
+ The config module's default export must satisfy the CodegenConfig type:
69
+
70
+ export default {
71
+ proxyName: "lexoffice",
72
+ upstreamUrl: process.env.LEXOFFICE_CODEGEN_SOURCE_URL,
73
+ auth: { mode: "bearer", token: process.env.LEXOFFICE_CODEGEN_TOKEN },
74
+ out: "./src/generated",
75
+ }
76
+ `);
77
+ }
78
+ async function loadConfig(configPath) {
79
+ const abs = path.resolve(process.cwd(), configPath);
80
+ const mod = (await import(pathToFileURL(abs).href));
81
+ if (!mod.default) {
82
+ throw new Error(`codegen config at ${abs} has no default export`);
83
+ }
84
+ return mod.default;
85
+ }
86
+ async function runGenerate(args) {
87
+ const configPath = args.config ?? "./codegen.config.ts";
88
+ const config = await loadConfig(configPath);
89
+ const result = await generateTools(config);
90
+ if (args.check) {
91
+ const tmp = await fs.mkdtemp(path.join(os.tmpdir(), "mcp-tool-codegen-"));
92
+ try {
93
+ const clone = { ...config, out: tmp };
94
+ await writeCodegenOutput(clone, result);
95
+ await assertMatches(config.out, tmp);
96
+ console.log(`OK (${result.tools.length} tools match committed output)`);
97
+ }
98
+ finally {
99
+ await fs.rm(tmp, { recursive: true, force: true });
100
+ }
101
+ return;
102
+ }
103
+ await writeCodegenOutput(config, result);
104
+ console.log(`generated ${result.tools.length} tools → ${path.resolve(process.cwd(), config.out)}`);
105
+ }
106
+ async function assertMatches(committed, generated) {
107
+ const committedAbs = path.resolve(process.cwd(), committed);
108
+ let drifted = false;
109
+ for (const file of ["tools.ts", "hooks.tsx"]) {
110
+ const a = await fs.readFile(path.join(committedAbs, file), "utf-8").catch(() => null);
111
+ const b = await fs.readFile(path.join(generated, file), "utf-8");
112
+ if (a === null) {
113
+ console.error(`drift: ${file} missing from committed output (${committedAbs})`);
114
+ drifted = true;
115
+ continue;
116
+ }
117
+ if (a !== b) {
118
+ console.error(`drift: ${file} differs from committed output`);
119
+ printLineDiff(a, b);
120
+ drifted = true;
121
+ }
122
+ }
123
+ if (drifted)
124
+ process.exit(1);
125
+ }
126
+ /**
127
+ * Prints the first N differing lines between two strings. Cheap line-level
128
+ * diff (no LCS) — sufficient to tell the user where regeneration would
129
+ * change the file without pulling in a diff library.
130
+ */
131
+ function printLineDiff(committed, generated, maxLines = 20) {
132
+ const aLines = committed.split("\n");
133
+ const bLines = generated.split("\n");
134
+ const max = Math.max(aLines.length, bLines.length);
135
+ let shown = 0;
136
+ for (let i = 0; i < max && shown < maxLines; i++) {
137
+ const a = aLines[i];
138
+ const b = bLines[i];
139
+ if (a !== b) {
140
+ if (a !== undefined)
141
+ console.error(` - ${i + 1}: ${a}`);
142
+ if (b !== undefined)
143
+ console.error(` + ${i + 1}: ${b}`);
144
+ shown++;
145
+ }
146
+ }
147
+ if (shown >= maxLines) {
148
+ console.error(` ... (truncated; more differences not shown)`);
149
+ }
150
+ }
151
+ async function runInspect(args) {
152
+ if (!args.upstream) {
153
+ console.error("inspect: --upstream <url> is required");
154
+ process.exit(1);
155
+ }
156
+ const auth = resolveAuthFromFlags(args);
157
+ const tools = await fetchUpstreamTools({ upstreamUrl: args.upstream, auth });
158
+ console.log(`| name | description | input keys |`);
159
+ console.log(`| --- | --- | --- |`);
160
+ for (const tool of tools) {
161
+ const inputKeys = Object.keys(tool.inputSchema.properties ?? {});
162
+ const desc = (tool.description ?? "").replace(/\|/g, "\\|").replace(/\n/g, " ");
163
+ console.log(`| ${tool.name} | ${desc} | ${inputKeys.join(", ")} |`);
164
+ }
165
+ }
166
+ function resolveAuthFromFlags(args) {
167
+ if (args.token)
168
+ return { mode: "bearer", token: args.token };
169
+ if (args.header && args.headerValue) {
170
+ return { mode: "header", headerName: args.header, value: args.headerValue };
171
+ }
172
+ return { mode: "none" };
173
+ }
174
+ async function main() {
175
+ const args = parseArgs(process.argv.slice(2));
176
+ try {
177
+ if (args.command === "help") {
178
+ printHelp();
179
+ return;
180
+ }
181
+ if (args.command === "generate")
182
+ return await runGenerate(args);
183
+ if (args.command === "inspect")
184
+ return await runInspect(args);
185
+ }
186
+ catch (err) {
187
+ console.error(err instanceof Error ? err.message : err);
188
+ process.exit(1);
189
+ }
190
+ }
191
+ void main();
192
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,+BAA+B;AAC/B,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAsB,MAAM,cAAc,CAAA;AACpF,OAAO,EAAE,kBAAkB,EAA0B,MAAM,kBAAkB,CAAA;AAc7E,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,IAAI,GAAe,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;IAC1D,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAA;IAC/B,IAAI,OAAO,KAAK,UAAU,IAAI,OAAO,KAAK,SAAS;QAAE,IAAI,CAAC,OAAO,GAAG,OAAO,CAAA;IAE3E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;QACnB,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAA;QAC5B,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,UAAU,CAAC;YAChB,KAAK,IAAI;gBACP,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,CAAA;gBACpB,MAAK;YACP,KAAK,SAAS;gBACZ,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;gBACjB,MAAK;YACP,KAAK,YAAY,CAAC;YAClB,KAAK,IAAI;gBACP,IAAI,CAAC,QAAQ,GAAG,IAAI,EAAE,CAAA;gBACtB,MAAK;YACP,KAAK,SAAS;gBACZ,IAAI,CAAC,KAAK,GAAG,IAAI,EAAE,CAAA;gBACnB,MAAK;YACP,KAAK,UAAU;gBACb,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,CAAA;gBACpB,MAAK;YACP,KAAK,gBAAgB;gBACnB,IAAI,CAAC,WAAW,GAAG,IAAI,EAAE,CAAA;gBACzB,MAAK;YACP,KAAK,OAAO,CAAC;YACb,KAAK,IAAI;gBACP,IAAI,CAAC,GAAG,GAAG,IAAI,EAAE,CAAA;gBACjB,MAAK;YACP,KAAK,SAAS,CAAC;YACf,KAAK,IAAI;gBACP,IAAI,CAAC,SAAS,GAAG,IAAI,EAAE,CAAA;gBACvB,MAAK;YACP,KAAK,QAAQ,CAAC;YACd,KAAK,IAAI;gBACP,IAAI,CAAC,OAAO,GAAG,MAAM,CAAA;gBACrB,MAAK;QACT,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CACT;;;;;;;;;;;;;;;;;;;;;CAqBH,CACE,CAAA;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,UAAkB;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC,CAAA;IACnD,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAgC,CAAA;IAClF,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,wBAAwB,CAAC,CAAA;IACnE,CAAC;IACD,OAAO,GAAG,CAAC,OAAO,CAAA;AACpB,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAgB;IACzC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,IAAI,qBAAqB,CAAA;IACvD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAA;IAC3C,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,CAAC,CAAA;IAE1C,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,mBAAmB,CAAC,CAAC,CAAA;QACzE,IAAI,CAAC;YACH,MAAM,KAAK,GAAkB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAA;YACpD,MAAM,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YACvC,MAAM,aAAa,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;YACpC,OAAO,CAAC,GAAG,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,gCAAgC,CAAC,CAAA;QACzE,CAAC;gBAAS,CAAC;YACT,MAAM,EAAE,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;QACpD,CAAC;QACD,OAAM;IACR,CAAC;IAED,MAAM,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACxC,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,KAAK,CAAC,MAAM,YAAY,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;AACpG,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,SAAiB,EAAE,SAAiB;IAC/D,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC,CAAA;IAC3D,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;QAC7C,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;QACrF,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAA;QAChE,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,mCAAmC,YAAY,GAAG,CAAC,CAAA;YAC/E,OAAO,GAAG,IAAI,CAAA;YACd,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,UAAU,IAAI,gCAAgC,CAAC,CAAA;YAC7D,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YACnB,OAAO,GAAG,IAAI,CAAA;QAChB,CAAC;IACH,CAAC;IACD,IAAI,OAAO;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAC9B,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CAAC,SAAiB,EAAE,SAAiB,EAAE,QAAQ,GAAG,EAAE;IACxE,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACpC,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAA;IAClD,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;QACnB,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;QACnB,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACZ,IAAI,CAAC,KAAK,SAAS;gBAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YACxD,IAAI,CAAC,KAAK,SAAS;gBAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;YACxD,KAAK,EAAE,CAAA;QACT,CAAC;IACH,CAAC;IACD,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAC;QACtB,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAChE,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAgB;IACxC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAA;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IACD,MAAM,IAAI,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,EAAE,WAAW,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5E,OAAO,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAA;IAClD,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAA;IAClC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAC1B,IAAI,CAAC,WAAW,CAAC,UAAkD,IAAI,EAAE,CAC3E,CAAA;QACD,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;QAC/E,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,MAAM,IAAI,MAAM,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACrE,CAAC;AACH,CAAC;AAED,SAAS,oBAAoB,CAAC,IAAgB;IAC5C,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;IAC5D,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,WAAW,EAAE,CAAC;QACpC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,CAAA;IAC7E,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAA;AACzB,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7C,IAAI,CAAC;QACH,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAC5B,SAAS,EAAE,CAAA;YACX,OAAM;QACR,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,KAAK,UAAU;YAAE,OAAO,MAAM,WAAW,CAAC,IAAI,CAAC,CAAA;QAC/D,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS;YAAE,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC,CAAA;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,KAAK,IAAI,EAAE,CAAA"}
@@ -0,0 +1,50 @@
1
+ import { type FetchToolsOptions, type UpstreamToolDescriptor } from "./fetch-tools.js";
2
+ export interface CodegenConfig {
3
+ /** Namespace prefix for the generated tool names and type names (`<proxyName>_<tool>`). */
4
+ proxyName: string;
5
+ upstreamUrl: string;
6
+ auth?: FetchToolsOptions["auth"];
7
+ /** Output directory (relative paths resolve against process.cwd()). */
8
+ out: string;
9
+ /**
10
+ * Optional per-tool type overrides. Keys are full tool names
11
+ * (`<proxy>_<tool>`), values are literal TypeScript type expressions
12
+ * that replace the codegen output for that tool.
13
+ *
14
+ * Useful when the upstream omits `outputSchema` — generated output type
15
+ * defaults to `unknown`, an override lets you paste a hand-written
16
+ * result shape without editing the generated file.
17
+ */
18
+ overrides?: Record<string, {
19
+ input?: string;
20
+ output?: string;
21
+ }>;
22
+ }
23
+ export interface CodegenResult {
24
+ toolsFile: string;
25
+ hooksFile: string;
26
+ tools: UpstreamToolDescriptor[];
27
+ }
28
+ /**
29
+ * Fetches `tools/list` from the upstream MCP, runs `json-schema-to-typescript`
30
+ * on each tool's input/output schemas, and renders the two generated files
31
+ * from the shipped Handlebars templates.
32
+ *
33
+ * Called by the CLI (`mcp-tool-codegen generate`) but exposed programmatically
34
+ * so consumers can wire it into custom build pipelines or tests.
35
+ */
36
+ export declare function generateTools(config: CodegenConfig): Promise<CodegenResult>;
37
+ /**
38
+ * Renders the two generated files from an explicit list of upstream tools —
39
+ * the pure, network-free half of {@link generateTools}. Split out so the
40
+ * build-time↔runtime naming/output contract can be pinned by a test that feeds
41
+ * a fixed tool list, instead of reaching for a live upstream.
42
+ *
43
+ * Sorts by tool name so two regenerations against the same upstream produce
44
+ * byte-identical output regardless of the upstream's `tools/list` order.
45
+ */
46
+ export declare function renderCodegen(fetched: UpstreamToolDescriptor[], config: CodegenConfig): Promise<CodegenResult>;
47
+ export declare function toPascalCase(input: string): string;
48
+ /** Resolve an output path against cwd, creating the directory if needed. */
49
+ export declare function writeCodegenOutput(config: CodegenConfig, result: CodegenResult): Promise<void>;
50
+ //# sourceMappingURL=codegen.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"AAQA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,sBAAsB,EAC5B,MAAM,kBAAkB,CAAA;AAEzB,MAAM,WAAW,aAAa;IAC5B,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,CAAC,EAAE,iBAAiB,CAAC,MAAM,CAAC,CAAA;IAChC,uEAAuE;IACvE,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAChE;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,sBAAsB,EAAE,CAAA;CAChC;AAED;;;;;;;GAOG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAMjF;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,sBAAsB,EAAE,EACjC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,aAAa,CAAC,CA2BxB;AAmED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAaD,4EAA4E;AAC5E,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,IAAI,CAAC,CAOf"}
@@ -0,0 +1,132 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import Handlebars from "handlebars";
5
+ import { compile as compileJsonSchema, } from "json-schema-to-typescript";
6
+ import { fetchUpstreamTools, } from "./fetch-tools.js";
7
+ /**
8
+ * Fetches `tools/list` from the upstream MCP, runs `json-schema-to-typescript`
9
+ * on each tool's input/output schemas, and renders the two generated files
10
+ * from the shipped Handlebars templates.
11
+ *
12
+ * Called by the CLI (`mcp-tool-codegen generate`) but exposed programmatically
13
+ * so consumers can wire it into custom build pipelines or tests.
14
+ */
15
+ export async function generateTools(config) {
16
+ const fetched = await fetchUpstreamTools({
17
+ upstreamUrl: config.upstreamUrl,
18
+ auth: config.auth,
19
+ });
20
+ return renderCodegen(fetched, config);
21
+ }
22
+ /**
23
+ * Renders the two generated files from an explicit list of upstream tools —
24
+ * the pure, network-free half of {@link generateTools}. Split out so the
25
+ * build-time↔runtime naming/output contract can be pinned by a test that feeds
26
+ * a fixed tool list, instead of reaching for a live upstream.
27
+ *
28
+ * Sorts by tool name so two regenerations against the same upstream produce
29
+ * byte-identical output regardless of the upstream's `tools/list` order.
30
+ */
31
+ export async function renderCodegen(fetched, config) {
32
+ const tools = [...fetched].sort((a, b) => a.name.localeCompare(b.name));
33
+ const proxyPascal = toPascalCase(config.proxyName);
34
+ const toolMapName = `${proxyPascal}ToolMap`;
35
+ const toolNameTypeName = `${proxyPascal}ToolName`;
36
+ const callToolTypeName = `${proxyPascal}CallTool`;
37
+ const view = {
38
+ proxyName: config.proxyName,
39
+ upstreamUrl: config.upstreamUrl,
40
+ toolMapName,
41
+ toolNameTypeName,
42
+ callToolTypeName,
43
+ tools: await Promise.all(tools.map((tool) => renderTool(tool, config, proxyPascal))),
44
+ };
45
+ const [toolsTpl, hooksTpl] = await Promise.all([
46
+ loadTemplate("tools.ts.hbs"),
47
+ loadTemplate("hooks.tsx.hbs"),
48
+ ]);
49
+ return {
50
+ toolsFile: normalizeEof(toolsTpl(view)),
51
+ hooksFile: normalizeEof(hooksTpl(view)),
52
+ tools,
53
+ };
54
+ }
55
+ /**
56
+ * Exactly one trailing newline, so committed output passes the repo's
57
+ * Prettier gate while staying byte-identical to `generate --check`.
58
+ */
59
+ function normalizeEof(rendered) {
60
+ return rendered.replace(/\n*$/, "\n");
61
+ }
62
+ async function renderTool(tool, config, proxyPascal) {
63
+ const toolPascal = toPascalCase(tool.name);
64
+ const inputTypeName = `${proxyPascal}${toolPascal}Input`;
65
+ const outputTypeName = `${proxyPascal}${toolPascal}Output`;
66
+ const fullName = `${config.proxyName}_${tool.name}`;
67
+ const override = config.overrides?.[fullName];
68
+ const inputTypeBody = override?.input
69
+ ? undefined
70
+ : await schemaToType(tool.inputSchema, inputTypeName);
71
+ const outputTypeBody = override?.output
72
+ ? undefined
73
+ : tool.outputSchema
74
+ ? await schemaToType(tool.outputSchema, outputTypeName)
75
+ : undefined;
76
+ const inputTypeRef = override?.input ?? (inputTypeBody ? inputTypeName : "unknown");
77
+ const outputTypeRef = override?.output ?? (outputTypeBody ? outputTypeName : "unknown");
78
+ return {
79
+ name: tool.name,
80
+ fullName,
81
+ quotedFullName: JSON.stringify(fullName),
82
+ hookName: `use${proxyPascal}${toolPascal}`,
83
+ inputTypeBody,
84
+ outputTypeBody,
85
+ inputTypeRef,
86
+ outputTypeRef,
87
+ // Prettier-style spacing so committed output passes the repo's format gate
88
+ // without breaking `generate --check`'s byte comparison.
89
+ queryKey: `[${JSON.stringify(config.proxyName)}, ${JSON.stringify(tool.name)}]`,
90
+ };
91
+ }
92
+ const json2tsOptions = {
93
+ bannerComment: "",
94
+ additionalProperties: false,
95
+ style: { singleQuote: false, semi: false },
96
+ unreachableDefinitions: false,
97
+ };
98
+ async function schemaToType(schema, name) {
99
+ const result = await compileJsonSchema(
100
+ // json-schema-to-typescript treats the top-level title as the type name,
101
+ // and `title` beats the `name` arg to `compile()`. Spread first so an
102
+ // upstream-supplied title can't override the codegen's chosen name.
103
+ { ...schema, title: name }, name, json2tsOptions);
104
+ return result.trim();
105
+ }
106
+ export function toPascalCase(input) {
107
+ return input
108
+ .split(/[-_\s]+/)
109
+ .filter(Boolean)
110
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
111
+ .join("");
112
+ }
113
+ let templateDir;
114
+ async function loadTemplate(name) {
115
+ if (!templateDir) {
116
+ const here = path.dirname(fileURLToPath(import.meta.url));
117
+ // dist/codegen.js → ../templates
118
+ templateDir = path.resolve(here, "..", "templates");
119
+ }
120
+ const src = await fs.readFile(path.join(templateDir, name), "utf-8");
121
+ return Handlebars.compile(src, { noEscape: true });
122
+ }
123
+ /** Resolve an output path against cwd, creating the directory if needed. */
124
+ export async function writeCodegenOutput(config, result) {
125
+ const outDir = path.resolve(process.cwd(), config.out);
126
+ await fs.mkdir(outDir, { recursive: true });
127
+ await Promise.all([
128
+ fs.writeFile(path.join(outDir, "tools.ts"), result.toolsFile),
129
+ fs.writeFile(path.join(outDir, "hooks.tsx"), result.hooksFile),
130
+ ]);
131
+ }
132
+ //# sourceMappingURL=codegen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codegen.js","sourceRoot":"","sources":["../src/codegen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export interface UpstreamToolDescriptor {
2
+ name: string;
3
+ description?: string;
4
+ title?: string;
5
+ inputSchema: Record<string, unknown>;
6
+ outputSchema?: Record<string, unknown>;
7
+ }
8
+ export interface FetchToolsOptions {
9
+ upstreamUrl: string;
10
+ /**
11
+ * Static auth for the build-time handshake. OAuth2 is not supported here —
12
+ * run the OAuth2 flow once in dev, paste the resulting access token, and
13
+ * use `{ mode: "bearer", token }` for subsequent regenerations.
14
+ */
15
+ auth?: {
16
+ mode: "none";
17
+ } | {
18
+ mode: "bearer";
19
+ token: string;
20
+ } | {
21
+ mode: "header";
22
+ headerName: string;
23
+ value: string;
24
+ };
25
+ /** Optional request headers to merge on top of the auth header. */
26
+ headers?: Record<string, string>;
27
+ }
28
+ /**
29
+ * Connects to an upstream MCP server over streamable HTTP, performs the
30
+ * initialize handshake, and returns the `tools/list` response. The
31
+ * connection is closed before returning.
32
+ *
33
+ * Used by the codegen CLI (`generate` / `inspect`) to snapshot a source
34
+ * server's tool surface. Build-time only — not intended for request-path
35
+ * use at runtime.
36
+ */
37
+ export declare function fetchUpstreamTools(options: FetchToolsOptions): Promise<UpstreamToolDescriptor[]>;
38
+ //# sourceMappingURL=fetch-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-tools.d.ts","sourceRoot":"","sources":["../src/fetch-tools.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB;;;;OAIG;IACH,IAAI,CAAC,EACD;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,GAChB;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GACjC;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACzD,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACjC;AAQD;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAqBnC"}
@@ -0,0 +1,41 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
3
+ function authHeaders(auth) {
4
+ if (!auth || auth.mode === "none")
5
+ return {};
6
+ if (auth.mode === "bearer")
7
+ return { authorization: `Bearer ${auth.token}` };
8
+ return { [auth.headerName.toLowerCase()]: auth.value };
9
+ }
10
+ /**
11
+ * Connects to an upstream MCP server over streamable HTTP, performs the
12
+ * initialize handshake, and returns the `tools/list` response. The
13
+ * connection is closed before returning.
14
+ *
15
+ * Used by the codegen CLI (`generate` / `inspect`) to snapshot a source
16
+ * server's tool surface. Build-time only — not intended for request-path
17
+ * use at runtime.
18
+ */
19
+ export async function fetchUpstreamTools(options) {
20
+ const url = new URL(options.upstreamUrl);
21
+ const requestInit = {
22
+ headers: { ...authHeaders(options.auth), ...(options.headers ?? {}) },
23
+ };
24
+ const transport = new StreamableHTTPClientTransport(url, { requestInit });
25
+ const client = new Client({ name: "mcp-tool-codegen", version: "0.1.0" }, { capabilities: {} });
26
+ try {
27
+ await client.connect(transport);
28
+ const result = await client.listTools();
29
+ return result.tools.map((t) => ({
30
+ name: t.name,
31
+ description: t.description,
32
+ title: t.title,
33
+ inputSchema: t.inputSchema,
34
+ outputSchema: t.outputSchema,
35
+ }));
36
+ }
37
+ finally {
38
+ await client.close().catch(() => { });
39
+ }
40
+ }
41
+ //# sourceMappingURL=fetch-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-tools.js","sourceRoot":"","sources":["../src/fetch-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAA;AAClE,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAyBlG,SAAS,WAAW,CAAC,IAA+B;IAClD,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,CAAA;IAC5C,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,EAAE,EAAE,CAAA;IAC5E,OAAO,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,CAAA;AACxD,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAA0B;IAE1B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IACxC,MAAM,WAAW,GAAgB;QAC/B,OAAO,EAAE,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE;KACtE,CAAA;IACD,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC,CAAA;IACzE,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAA;IAE/F,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;QAC/B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,SAAS,EAAE,CAAA;QACvC,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,YAAY,EAAE,CAAC,CAAC,YAAY;SAC7B,CAAC,CAAC,CAAA;IACL,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAA;IACtC,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ export type { ToolShape, TypedCallTool } from "./runtime.js";
2
+ export { fetchUpstreamTools } from "./fetch-tools.js";
3
+ export type { FetchToolsOptions, UpstreamToolDescriptor } from "./fetch-tools.js";
4
+ export { generateTools, renderCodegen, writeCodegenOutput } from "./codegen.js";
5
+ export type { CodegenConfig, CodegenResult } from "./codegen.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AACrD,YAAY,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AACjF,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAC/E,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { fetchUpstreamTools } from "./fetch-tools.js";
2
+ export { generateTools, renderCodegen, writeCodegenOutput } from "./codegen.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Runtime types referenced by codegen output. Kept in their own subpath
3
+ * (`@miragon/mcp-toolkit-tool-codegen/runtime`) so widget bundles and
4
+ * step modules can import the types without pulling in the CLI / codegen
5
+ * dependencies (handlebars, json-schema-to-typescript).
6
+ */
7
+ export interface ToolShape {
8
+ input: unknown;
9
+ output: unknown;
10
+ }
11
+ /**
12
+ * A typed `callTool` closure bound to a specific upstream-MCP's tool map.
13
+ * The `TMap` type is filled in by the generated `<Proxy>ToolMap` interface;
14
+ * consumers write `TypedCallTool<LexofficeToolMap>` and get auto-completion
15
+ * plus compile-time validation on tool names, args, and results.
16
+ *
17
+ * Surface is deliberately 2-arg — the framework pipeline executor injects
18
+ * the caller's userId behind the scenes so step code stays clean.
19
+ */
20
+ export type TypedCallTool<TMap extends Record<string, ToolShape>> = <TName extends keyof TMap & string>(name: TName, args: TMap[TName]["input"]) => Promise<TMap[TName]["output"]>;
21
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,CAAC,IAAI,SAAS,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,IAAI,CAClE,KAAK,SAAS,MAAM,IAAI,GAAG,MAAM,EAEjC,IAAI,EAAE,KAAK,EACX,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KACvB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Runtime types referenced by codegen output. Kept in their own subpath
3
+ * (`@miragon/mcp-toolkit-tool-codegen/runtime`) so widget bundles and
4
+ * step modules can import the types without pulling in the CLI / codegen
5
+ * dependencies (handlebars, json-schema-to-typescript).
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@miragon/mcp-toolkit-tool-codegen",
3
+ "version": "0.10.1",
4
+ "description": "Build-time codegen + runtime glue for type-safe MCP tool calls: TypedCallTool helper and a CLI that generates TypeScript types + React Query hooks from an MCP server's tools/list.",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "main": "dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "bin": {
10
+ "mcp-tool-codegen": "dist/cli.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./runtime": {
18
+ "types": "./dist/runtime.d.ts",
19
+ "import": "./dist/runtime.js"
20
+ },
21
+ "./templates/*": "./templates/*"
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "templates",
26
+ "README.md"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "peerDependencies": {
32
+ "@modelcontextprotocol/sdk": "1.29.0",
33
+ "@miragon/mcp-toolkit-core": "0.10.1"
34
+ },
35
+ "dependencies": {
36
+ "handlebars": "4.7.9",
37
+ "json-schema-to-typescript": "15.0.4"
38
+ },
39
+ "devDependencies": {
40
+ "@modelcontextprotocol/sdk": "1.29.0",
41
+ "@types/node": "26.1.1",
42
+ "typescript": "6.0.3",
43
+ "vitest": "4.1.10",
44
+ "@miragon/mcp-toolkit-core": "0.10.1"
45
+ },
46
+ "scripts": {
47
+ "build": "tsc -p tsconfig.build.json && node scripts/make-cli-executable.mjs",
48
+ "typecheck": "tsc --noEmit",
49
+ "test": "vitest run",
50
+ "lint": "eslint src --max-warnings 0",
51
+ "lint:fix": "eslint src --fix"
52
+ }
53
+ }
@@ -0,0 +1,22 @@
1
+ // AUTO-GENERATED by @miragon/mcp-toolkit-tool-codegen. Do not edit by hand.
2
+ // Regenerate with: pnpm mcp-tool-codegen generate
3
+ // Source: {{upstreamUrl}}
4
+ // Proxy: {{proxyName}}
5
+
6
+ import { useToolQuery, type UseToolQueryOptions } from "@miragon/mcp-toolkit-ui"
7
+ import type { {{toolMapName}} } from "./tools.js"
8
+
9
+ {{#each tools}}
10
+ export function {{hookName}}(
11
+ args: {{../toolMapName}}[{{{quotedFullName}}}]["input"],
12
+ options?: UseToolQueryOptions<{{../toolMapName}}[{{{quotedFullName}}}]["output"]>,
13
+ ) {
14
+ return useToolQuery<{{../toolMapName}}[{{{quotedFullName}}}]["output"]>(
15
+ {{{queryKey}}},
16
+ {{{quotedFullName}}},
17
+ args,
18
+ options,
19
+ )
20
+ }
21
+
22
+ {{/each}}
@@ -0,0 +1,28 @@
1
+ // AUTO-GENERATED by @miragon/mcp-toolkit-tool-codegen. Do not edit by hand.
2
+ // Regenerate with: pnpm mcp-tool-codegen generate
3
+ // Source: {{upstreamUrl}}
4
+ // Proxy: {{proxyName}}
5
+ /* eslint-disable @typescript-eslint/no-empty-object-type */
6
+
7
+ import type { ToolShape, TypedCallTool } from "@miragon/mcp-toolkit-tool-codegen/runtime"
8
+
9
+ {{#each tools}}
10
+ {{#if inputTypeBody}}
11
+ {{{inputTypeBody}}}
12
+ {{/if}}
13
+ {{#if outputTypeBody}}
14
+ {{{outputTypeBody}}}
15
+ {{/if}}
16
+ {{/each}}
17
+
18
+ export interface {{toolMapName}} extends Record<string, ToolShape> {
19
+ {{#each tools}}
20
+ {{{quotedFullName}}}: {
21
+ input: {{inputTypeRef}}
22
+ output: {{outputTypeRef}}
23
+ }
24
+ {{/each}}
25
+ }
26
+
27
+ export type {{toolNameTypeName}} = keyof {{toolMapName}} & string
28
+ export type {{callToolTypeName}} = TypedCallTool<{{toolMapName}}>