@kubb/mcp 5.0.0-alpha.8 → 5.0.0-beta.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/dist/index.js CHANGED
@@ -4,11 +4,12 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
  import { z } from "zod";
6
6
  import { EventEmitter } from "node:events";
7
+ import { existsSync } from "node:fs";
7
8
  import path from "node:path";
8
- import { safeBuild, setup } from "@kubb/core";
9
- import createJiti from "jiti";
9
+ import { createKubb } from "@kubb/core";
10
+ import { unrun } from "unrun";
10
11
  //#region package.json
11
- var version = "5.0.0-alpha.8";
12
+ var version = "5.0.0-beta.1";
12
13
  //#endregion
13
14
  //#region src/schemas/generateSchema.ts
14
15
  const generateSchema = z.object({
@@ -28,8 +29,14 @@ const generateSchema = z.object({
28
29
  //#region ../../internals/utils/src/errors.ts
29
30
  /**
30
31
  * Coerces an unknown thrown value to an `Error` instance.
31
- * When the value is already an `Error` it is returned as-is;
32
- * otherwise a new `Error` is created whose message is `String(value)`.
32
+ * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * try { ... } catch(err) {
37
+ * throw new BuildError('Build failed', { cause: toError(err), errors: [] })
38
+ * }
39
+ * ```
33
40
  */
34
41
  function toError(value) {
35
42
  return value instanceof Error ? value : new Error(String(value));
@@ -37,12 +44,19 @@ function toError(value) {
37
44
  //#endregion
38
45
  //#region ../../internals/utils/src/asyncEventEmitter.ts
39
46
  /**
40
- * A typed EventEmitter that awaits all async listeners before resolving.
47
+ * Typed `EventEmitter` that awaits all async listeners before resolving.
41
48
  * Wraps Node's `EventEmitter` with full TypeScript event-map inference.
49
+ *
50
+ * @example
51
+ * ```ts
52
+ * const emitter = new AsyncEventEmitter<{ build: [name: string] }>()
53
+ * emitter.on('build', async (name) => { console.log(name) })
54
+ * await emitter.emit('build', 'petstore') // all listeners awaited
55
+ * ```
42
56
  */
43
57
  var AsyncEventEmitter = class {
44
58
  /**
45
- * `maxListener` controls the maximum number of listeners per event before Node emits a memory-leak warning.
59
+ * Maximum number of listeners per event before Node emits a memory-leak warning.
46
60
  * @default 10
47
61
  */
48
62
  constructor(maxListener = 10) {
@@ -50,31 +64,48 @@ var AsyncEventEmitter = class {
50
64
  }
51
65
  #emitter = new EventEmitter();
52
66
  /**
53
- * Emits an event and awaits all registered listeners in parallel.
67
+ * Emits `eventName` and awaits all registered listeners sequentially.
54
68
  * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.
69
+ *
70
+ * @example
71
+ * ```ts
72
+ * await emitter.emit('build', 'petstore')
73
+ * ```
55
74
  */
56
75
  async emit(eventName, ...eventArgs) {
57
76
  const listeners = this.#emitter.listeners(eventName);
58
77
  if (listeners.length === 0) return;
59
- await Promise.all(listeners.map(async (listener) => {
78
+ for (const listener of listeners) try {
79
+ await listener(...eventArgs);
80
+ } catch (err) {
81
+ let serializedArgs;
60
82
  try {
61
- return await listener(...eventArgs);
62
- } catch (err) {
63
- let serializedArgs;
64
- try {
65
- serializedArgs = JSON.stringify(eventArgs);
66
- } catch {
67
- serializedArgs = String(eventArgs);
68
- }
69
- throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
83
+ serializedArgs = JSON.stringify(eventArgs);
84
+ } catch {
85
+ serializedArgs = String(eventArgs);
70
86
  }
71
- }));
87
+ throw new Error(`Error in async listener for "${eventName}" with eventArgs ${serializedArgs}`, { cause: toError(err) });
88
+ }
72
89
  }
73
- /** Registers a persistent listener for the given event. */
90
+ /**
91
+ * Registers a persistent listener for `eventName`.
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * emitter.on('build', async (name) => { console.log(name) })
96
+ * ```
97
+ */
74
98
  on(eventName, handler) {
75
99
  this.#emitter.on(eventName, handler);
76
100
  }
77
- /** Registers a one-shot listener that removes itself after the first invocation. */
101
+ /**
102
+ * Registers a one-shot listener that removes itself after the first invocation.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * emitter.onOnce('build', async (name) => { console.log(name) })
107
+ * ```
108
+ */
78
109
  onOnce(eventName, handler) {
79
110
  const wrapper = (...args) => {
80
111
  this.off(eventName, wrapper);
@@ -82,18 +113,51 @@ var AsyncEventEmitter = class {
82
113
  };
83
114
  this.on(eventName, wrapper);
84
115
  }
85
- /** Removes a previously registered listener. */
116
+ /**
117
+ * Removes a previously registered listener.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * emitter.off('build', handler)
122
+ * ```
123
+ */
86
124
  off(eventName, handler) {
87
125
  this.#emitter.off(eventName, handler);
88
126
  }
89
- /** Removes all listeners from every event channel. */
127
+ /**
128
+ * Returns the number of listeners registered for `eventName`.
129
+ *
130
+ * @example
131
+ * ```ts
132
+ * emitter.on('build', handler)
133
+ * emitter.listenerCount('build') // 1
134
+ * ```
135
+ */
136
+ listenerCount(eventName) {
137
+ return this.#emitter.listenerCount(eventName);
138
+ }
139
+ /**
140
+ * Removes all listeners from every event channel.
141
+ *
142
+ * @example
143
+ * ```ts
144
+ * emitter.removeAll()
145
+ * ```
146
+ */
90
147
  removeAll() {
91
148
  this.#emitter.removeAllListeners();
92
149
  }
93
150
  };
94
151
  //#endregion
95
152
  //#region ../../internals/utils/src/promise.ts
96
- /** Returns `true` when `result` is a thenable `Promise`. */
153
+ /** Returns `true` when `result` is a thenable `Promise`.
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * isPromise(Promise.resolve(1)) // true
158
+ * isPromise(42) // false
159
+ * ```
160
+ */
97
161
  function isPromise(result) {
98
162
  return result !== null && result !== void 0 && typeof result["then"] === "function";
99
163
  }
@@ -123,19 +187,48 @@ const NotifyTypes = {
123
187
  FATAL_ERROR: "FATAL_ERROR"
124
188
  };
125
189
  //#endregion
190
+ //#region src/constants.ts
191
+ const ALLOWED_CONFIG_EXTENSIONS = new Set([
192
+ ".ts",
193
+ ".mts",
194
+ ".cts",
195
+ ".js",
196
+ ".mjs",
197
+ ".cjs"
198
+ ]);
199
+ //#endregion
126
200
  //#region src/utils/loadUserConfig.ts
127
- const jiti = createJiti(import.meta.url, { sourceMaps: true });
128
- /**
129
- * Load the user configuration from the specified path or current directory
130
- */
201
+ const loadedModules = /* @__PURE__ */ new Map();
202
+ async function loadModule(filePath) {
203
+ const ext = path.extname(filePath);
204
+ if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) throw new Error(`Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(", ")}`);
205
+ if (loadedModules.has(filePath)) return loadedModules.get(filePath);
206
+ const { module } = await unrun({ path: filePath });
207
+ loadedModules.set(filePath, module);
208
+ return module;
209
+ }
131
210
  async function loadUserConfig(configPath, { notify }) {
132
211
  let userConfig;
133
212
  let cwd;
134
213
  if (configPath) {
135
- cwd = path.dirname(path.resolve(configPath));
214
+ const ext = path.extname(configPath);
215
+ if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {
216
+ const msg = `Invalid config file extension "${ext}". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(", ")}`;
217
+ await notify(NotifyTypes.CONFIG_ERROR, msg);
218
+ throw new Error(msg);
219
+ }
220
+ const base = path.resolve(process.cwd());
221
+ const resolvedConfigPath = path.resolve(base, configPath);
222
+ const relative = path.relative(base, resolvedConfigPath);
223
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
224
+ const msg = "Invalid config file path: must be within the current working directory";
225
+ await notify(NotifyTypes.CONFIG_ERROR, msg);
226
+ throw new Error(msg);
227
+ }
228
+ cwd = path.dirname(resolvedConfigPath);
136
229
  try {
137
- userConfig = await jiti.import(configPath, { default: true });
138
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${configPath}`);
230
+ userConfig = await loadModule(resolvedConfigPath);
231
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`);
139
232
  } catch (error) {
140
233
  await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
141
234
  throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
@@ -144,15 +237,20 @@ async function loadUserConfig(configPath, { notify }) {
144
237
  cwd = process.cwd();
145
238
  const configFileNames = [
146
239
  "kubb.config.ts",
240
+ "kubb.config.mts",
241
+ "kubb.config.cts",
147
242
  "kubb.config.js",
148
243
  "kubb.config.cjs"
149
244
  ];
150
- for (const configFileName of configFileNames) try {
245
+ for (const configFileName of configFileNames) {
151
246
  const configFilePath = path.resolve(process.cwd(), configFileName);
152
- userConfig = await jiti.import(configFilePath, { default: true });
153
- await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`);
154
- break;
155
- } catch {}
247
+ if (!existsSync(configFilePath)) continue;
248
+ try {
249
+ userConfig = await loadModule(configFilePath);
250
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`);
251
+ break;
252
+ } catch {}
253
+ }
156
254
  if (!userConfig) {
157
255
  await notify(NotifyTypes.CONFIG_ERROR, "No config file found");
158
256
  throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(", ")}`);
@@ -183,10 +281,10 @@ function resolveCwd(userConfig, cwd) {
183
281
  /**
184
282
  * Resolve the config by handling function configs and returning the final configuration
185
283
  */
186
- async function resolveUserConfig(userConfig, options) {
187
- let kubbUserConfig = Promise.resolve(userConfig);
188
- if (typeof userConfig === "function") {
189
- const possiblePromise = userConfig({
284
+ async function resolveUserConfig(config, options) {
285
+ let kubbUserConfig = Promise.resolve(config);
286
+ if (typeof config === "function") {
287
+ const possiblePromise = config({
190
288
  logLevel: options.logLevel,
191
289
  config: options.configPath
192
290
  });
@@ -204,7 +302,7 @@ async function resolveUserConfig(userConfig, options) {
204
302
  async function generate(schema, handler) {
205
303
  const { config: configPath, input, output, logLevel } = schema;
206
304
  try {
207
- const events = new AsyncEventEmitter();
305
+ const hooks = new AsyncEventEmitter();
208
306
  const messages = [];
209
307
  const notify = async (type, message, data) => {
210
308
  messages.push(`${type}: ${message}`);
@@ -215,37 +313,37 @@ async function generate(schema, handler) {
215
313
  ...data
216
314
  });
217
315
  };
218
- events.on("info", async (message) => {
316
+ hooks.on("kubb:info", async ({ message }) => {
219
317
  await notify(NotifyTypes.INFO, message);
220
318
  });
221
- events.on("success", async (message) => {
319
+ hooks.on("kubb:success", async ({ message }) => {
222
320
  await notify(NotifyTypes.SUCCESS, message);
223
321
  });
224
- events.on("error", async (error) => {
322
+ hooks.on("kubb:error", async ({ error }) => {
225
323
  await notify(NotifyTypes.ERROR, error.message, { stack: error.stack });
226
324
  });
227
- events.on("warn", async (message) => {
325
+ hooks.on("kubb:warn", async ({ message }) => {
228
326
  await notify(NotifyTypes.WARN, message);
229
327
  });
230
- events.on("plugin:start", async ({ name }) => {
231
- await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${name}`);
328
+ hooks.on("kubb:plugin:start", async ({ plugin }) => {
329
+ await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${plugin.name}`);
232
330
  });
233
- events.on("plugin:end", async ({ name, duration }) => {
234
- await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${name}`, { duration });
331
+ hooks.on("kubb:plugin:end", async ({ plugin, duration }) => {
332
+ await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${plugin.name}`, { duration });
235
333
  });
236
- events.on("files:processing:start", async () => {
334
+ hooks.on("kubb:files:processing:start", async () => {
237
335
  await notify(NotifyTypes.FILES_START, "Starting file processing");
238
336
  });
239
- events.on("file:processing:update", async ({ file }) => {
337
+ hooks.on("kubb:file:processing:update", async ({ file }) => {
240
338
  await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`);
241
339
  });
242
- events.on("files:processing:end", async () => {
340
+ hooks.on("kubb:files:processing:end", async () => {
243
341
  await notify(NotifyTypes.FILES_END, "File processing complete");
244
342
  });
245
- events.on("generation:start", async () => {
343
+ hooks.on("kubb:generation:start", async () => {
246
344
  await notify(NotifyTypes.GENERATION_START, "Generation started");
247
345
  });
248
- events.on("generation:end", async () => {
346
+ hooks.on("kubb:generation:end", async () => {
249
347
  await notify(NotifyTypes.GENERATION_END, "Generation ended");
250
348
  });
251
349
  let userConfig;
@@ -285,21 +383,11 @@ async function generate(schema, handler) {
285
383
  };
286
384
  await notify(NotifyTypes.CONFIG_READY, "Configuration ready", { root: config.root });
287
385
  await notify(NotifyTypes.SETUP_START, "Setting up Kubb");
288
- const { fabric, driver, sources } = await setup({
289
- config,
290
- events
291
- });
386
+ const kubb = createKubb(config, { hooks });
387
+ await kubb.setup();
292
388
  await notify(NotifyTypes.SETUP_END, "Kubb setup complete");
293
389
  await notify(NotifyTypes.BUILD_START, "Starting build");
294
- const { files, failedPlugins, error } = await safeBuild({
295
- config,
296
- events
297
- }, {
298
- driver,
299
- fabric,
300
- events,
301
- sources
302
- });
390
+ const { files, failedPlugins, error } = await kubb.safeBuild();
303
391
  await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`);
304
392
  if (error || failedPlugins.size > 0) {
305
393
  const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["#emitter","NodeEventEmitter"],"sources":["../package.json","../src/schemas/generateSchema.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/asyncEventEmitter.ts","../../../internals/utils/src/promise.ts","../src/types.ts","../src/utils/loadUserConfig.ts","../src/utils/resolveCwd.ts","../src/utils/resolveUserConfig.ts","../src/tools/generate.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["","import { z } from 'zod'\n\nexport const generateSchema = z.object({\n config: z\n .string()\n .optional()\n\n .describe('Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory'),\n input: z.string().optional().describe('Path to OpenAPI/Swagger spec file (overrides config)'),\n output: z.string().optional().describe('Output directory path (overrides config)'),\n logLevel: z.enum(['silent', 'error', 'warn', 'info', 'verbose', 'debug']).optional().default('info').describe('Log level for build output'),\n})\n\n","/** Thrown when a plugin's configuration or input fails validation. */\nexport class ValidationPluginError extends Error {}\n\n/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * When the value is already an `Error` it is returned as-is;\n * otherwise a new `Error` is created whose message is `String(value)`.\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Safely extracts a human-readable message from any thrown value.\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error | undefined`.\n * Returns `undefined` when the cause is absent or is not an `Error`.\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from './errors.ts'\n\n/** A function that can be registered as an event listener, synchronous or async. */\ntype AsyncListener<TArgs extends unknown[]> = (...args: TArgs) => void | Promise<void>\n\n/**\n * A typed EventEmitter that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript event-map inference.\n */\nexport class AsyncEventEmitter<TEvents extends { [K in keyof TEvents]: unknown[] }> {\n /**\n * `maxListener` controls the maximum number of listeners per event before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Emits an event and awaits all registered listeners in parallel.\n * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.\n */\n async emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArgs: TEvents[TEventName]): Promise<void> {\n const listeners = this.#emitter.listeners(eventName) as Array<AsyncListener<TEvents[TEventName]>>\n\n if (listeners.length === 0) {\n return undefined\n }\n\n await Promise.all(\n listeners.map(async (listener) => {\n try {\n return await listener(...eventArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(eventArgs)\n } catch {\n serializedArgs = String(eventArgs)\n }\n throw new Error(`Error in async listener for \"${eventName}\" with eventArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }),\n )\n }\n\n /** Registers a persistent listener for the given event. */\n on<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.on(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /** Registers a one-shot listener that removes itself after the first invocation. */\n onOnce<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n const wrapper: AsyncListener<TEvents[TEventName]> = (...args) => {\n this.off(eventName, wrapper)\n return handler(...args)\n }\n this.on(eventName, wrapper)\n }\n\n /** Removes a previously registered listener. */\n off<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.off(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /** Removes all listeners from every event channel. */\n removeAll(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","/** A value that may already be resolved or still pending. */\nexport type PossiblePromise<T> = Promise<T> | T\n\n/** Returns `true` when `result` is a thenable `Promise`. */\nexport function isPromise<T>(result: PossiblePromise<T>): result is Promise<T> {\n return result !== null && result !== undefined && typeof (result as Record<string, unknown>)['then'] === 'function'\n}\n\n/** Type guard for a fulfilled `Promise.allSettled` result. */\nexport function isPromiseFulfilledResult<T = unknown>(result: PromiseSettledResult<unknown>): result is PromiseFulfilledResult<T> {\n return result.status === 'fulfilled'\n}\n\n/** Type guard for a rejected `Promise.allSettled` result with a typed `reason`. */\nexport function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {\n return result.status === 'rejected'\n}\n","export const NotifyTypes = {\n INFO: 'INFO',\n SUCCESS: 'SUCCESS',\n ERROR: 'ERROR',\n WARN: 'WARN',\n PLUGIN_START: 'PLUGIN_START',\n PLUGIN_END: 'PLUGIN_END',\n FILES_START: 'FILES_START',\n FILE_UPDATE: 'FILE_UPDATE',\n FILES_END: 'FILES_END',\n GENERATION_START: 'GENERATION_START',\n GENERATION_END: 'GENERATION_END',\n CONFIG_LOADED: 'CONFIG_LOADED',\n CONFIG_ERROR: 'CONFIG_ERROR',\n CONFIG_READY: 'CONFIG_READY',\n SETUP_START: 'SETUP_START',\n SETUP_END: 'SETUP_END',\n BUILD_START: 'BUILD_START',\n BUILD_END: 'BUILD_END',\n BUILD_FAILED: 'BUILD_FAILED',\n BUILD_SUCCESS: 'BUILD_SUCCESS',\n FATAL_ERROR: 'FATAL_ERROR',\n} as const\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\nimport createJiti from 'jiti'\nimport { NotifyTypes } from '../types.ts'\n\ntype NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>\n\nconst jiti = createJiti(import.meta.url, {\n sourceMaps: true,\n})\n\n/**\n * Load the user configuration from the specified path or current directory\n */\nexport async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {\n let userConfig: Config | undefined\n let cwd: string\n\n if (configPath) {\n // Resolve the config path to absolute path and get its directory\n cwd = path.dirname(path.resolve(configPath))\n\n // Try to load from path\n try {\n userConfig = await jiti.import(configPath, { default: true })\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${configPath}`)\n } catch (error) {\n await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n }\n } else {\n // Look for kubb.config in current directory with various extensions\n cwd = process.cwd()\n const configFileNames = ['kubb.config.ts', 'kubb.config.js', 'kubb.config.cjs']\n\n for (const configFileName of configFileNames) {\n try {\n const configFilePath = path.resolve(process.cwd(), configFileName)\n userConfig = await jiti.import(configFilePath, { default: true })\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)\n break\n } catch {\n // Continue trying next config file\n }\n }\n\n if (!userConfig) {\n await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')\n\n throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)\n }\n }\n\n return { userConfig: userConfig!, cwd }\n}\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\n\n/**\n * Determine the root directory based on userConfig.root and resolvedConfigDir\n * 1. If userConfig.root exists and is absolute, use it as-is\n * 2. If userConfig.root exists and is relative, resolve it relative to config directory\n * 3. Otherwise, use the config directory as root\n */\nexport function resolveCwd(userConfig: Config, cwd: string): string {\n if (userConfig.root) {\n if (path.isAbsolute(userConfig.root)) {\n return userConfig.root\n }\n\n return path.resolve(cwd, userConfig.root)\n }\n\n return cwd\n}\n","import { isPromise } from '@internals/utils'\nimport type { CLIOptions, Config, UserConfig } from '@kubb/core'\n\nexport type ResolveUserConfigOptions = {\n configPath?: string\n logLevel?: string\n}\n\n/**\n * Resolve the config by handling function configs and returning the final configuration\n */\nexport async function resolveUserConfig(userConfig: UserConfig, options: ResolveUserConfigOptions): Promise<Config> {\n let kubbUserConfig = Promise.resolve(userConfig) as Promise<UserConfig>\n\n if (typeof userConfig === 'function') {\n const possiblePromise = (userConfig as any)({ logLevel: options.logLevel, config: options.configPath } as CLIOptions)\n if (isPromise(possiblePromise)) {\n kubbUserConfig = possiblePromise\n } else {\n kubbUserConfig = Promise.resolve(possiblePromise)\n }\n }\n\n return (await kubbUserConfig) as Config\n}\n","import { AsyncEventEmitter } from '@internals/utils'\nimport { type Config, type KubbEvents, safeBuild, setup } from '@kubb/core'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.d.ts'\nimport type { z } from 'zod'\nimport type { generateSchema } from '../schemas/generateSchema.ts'\nimport { NotifyTypes } from '../types.ts'\nimport { loadUserConfig } from '../utils/loadUserConfig.ts'\nimport { resolveCwd } from '../utils/resolveCwd.ts'\nimport { resolveUserConfig } from '../utils/resolveUserConfig.ts'\n\ninterface NotificationHandler {\n sendNotification(method: string, params: unknown): Promise<void>\n}\n\n/**\n * Build tool that generates code from OpenAPI specs using Kubb.\n * Sends real-time notifications of build progress and events.\n */\nexport async function generate(schema: z.infer<typeof generateSchema>, handler: NotificationHandler): Promise<CallToolResult> {\n const { config: configPath, input, output, logLevel } = schema\n\n try {\n const events = new AsyncEventEmitter<KubbEvents>()\n const messages: string[] = []\n\n // Helper to send notifications\n const notify = async (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(`${type}: ${message}`)\n\n await handler.sendNotification('kubb/progress', {\n type,\n message,\n timestamp: new Date().toISOString(),\n ...data,\n })\n }\n\n // Capture events for output and send notifications\n events.on('info', async (message: string) => {\n await notify(NotifyTypes.INFO, message)\n })\n\n events.on('success', async (message: string) => {\n await notify(NotifyTypes.SUCCESS, message)\n })\n\n events.on('error', async (error: Error) => {\n await notify(NotifyTypes.ERROR, error.message, { stack: error.stack })\n })\n\n events.on('warn', async (message: string) => {\n await notify(NotifyTypes.WARN, message)\n })\n\n // Plugin lifecycle events\n events.on('plugin:start', async ({ name }: { name: string }) => {\n await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${name}`)\n })\n\n events.on('plugin:end', async ({ name, duration }: { name: string; duration?: number }) => {\n await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${name}`, { duration })\n })\n\n // File processing events\n events.on('files:processing:start', async () => {\n await notify(NotifyTypes.FILES_START, 'Starting file processing')\n })\n\n events.on('file:processing:update', async ({ file }: { file: { name: string } }) => {\n await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`)\n })\n\n events.on('files:processing:end', async () => {\n await notify(NotifyTypes.FILES_END, 'File processing complete')\n })\n\n // Generation events\n events.on('generation:start', async () => {\n await notify(NotifyTypes.GENERATION_START, 'Generation started')\n })\n\n events.on('generation:end', async () => {\n await notify(NotifyTypes.GENERATION_END, 'Generation ended')\n })\n\n // Load and process configuration\n let userConfig: Config\n let cwd: string\n\n try {\n const configResult = await loadUserConfig(configPath, { notify })\n userConfig = configResult.userConfig\n cwd = configResult.cwd\n\n if (Array.isArray(userConfig) && userConfig.length) {\n throw new Error('Array type in kubb.config.ts is not supported in this tool. Please provide a single configuration object.')\n }\n\n userConfig = await resolveUserConfig(userConfig, { configPath, logLevel })\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n await notify(NotifyTypes.CONFIG_ERROR, errorMessage)\n return {\n content: [\n {\n type: 'text',\n text: errorMessage,\n },\n ],\n isError: true,\n }\n }\n\n const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)\n\n // Override config with CLI options\n const config: Config = {\n ...userConfig,\n root: resolveCwd(userConfig, cwd),\n input: inputPath\n ? {\n ...userConfig.input,\n path: inputPath,\n }\n : userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n await notify(NotifyTypes.CONFIG_READY, 'Configuration ready', {\n root: config.root,\n })\n\n // Setup and build\n await notify(NotifyTypes.SETUP_START, 'Setting up Kubb')\n\n const { fabric, driver, sources } = await setup({\n config,\n events,\n })\n await notify(NotifyTypes.SETUP_END, 'Kubb setup complete')\n\n await notify(NotifyTypes.BUILD_START, 'Starting build')\n const { files, failedPlugins, error } = await safeBuild(\n {\n config,\n events,\n },\n { driver, fabric, events, sources },\n )\n await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`)\n\n if (error || failedPlugins.size > 0) {\n const allErrors: Error[] = [\n error,\n ...Array.from(failedPlugins)\n .filter((it) => it.error)\n .map((it) => it.error),\n ].filter(Boolean)\n\n await notify(NotifyTypes.BUILD_FAILED, `Build failed with ${allErrors.length} error(s)`, {\n errorCount: allErrors.length,\n errors: allErrors.map((err) => err.message),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build failed:\\n${allErrors.map((err) => err.message).join('\\n')}\\n\\n${messages.join('\\n')}`,\n },\n ],\n isError: true,\n }\n }\n\n await notify(NotifyTypes.BUILD_SUCCESS, `Build completed successfully - Generated ${files.length} files`, {\n filesCount: files.length,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build completed successfully!\\n\\nGenerated ${files.length} files\\n\\n${messages.join('\\n')}`,\n },\n ],\n }\n } catch (caughtError) {\n const error = caughtError as Error\n\n await handler.sendNotification('kubb/progress', {\n type: NotifyTypes.FATAL_ERROR,\n message: error.message,\n stack: error.stack,\n timestamp: new Date().toISOString(),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build error: ${error.message}\\n${error.stack || ''}`,\n },\n ],\n isError: true,\n }\n }\n}\n","import process from 'node:process'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { version } from '../package.json'\nimport { generateSchema } from './schemas/generateSchema.ts'\nimport { generate } from './tools/generate.ts'\n\n/**\n * Kubb MCP Server\n *\n * Provides tools for building OpenAPI specifications using Kubb.\n */\nexport async function startServer() {\n try {\n const transport = new StdioServerTransport()\n const server = new McpServer({\n name: 'Kubb',\n version,\n })\n\n // Build tool - runs Kubb build using @kubb/core\n // Wrapped to pass notification handler for real-time progress updates\n server.tool('generate', 'Generate OpenAPI spec helpers using Kubb configuration', generateSchema.shape, async (args) => {\n // Create notification handler that sends events back to the client\n const notificationHandler = {\n sendNotification: async (method: string, params: any) => {\n try {\n await transport.send({\n jsonrpc: '2.0',\n method,\n params,\n })\n } catch (error) {\n console.error('Failed to send notification:', error)\n }\n },\n }\n\n // Call build tool with notification handler\n return generate(args, notificationHandler)\n })\n\n await server.connect(transport)\n } catch (error) {\n console.error('Failed to start MCP server:', error)\n process.exit(1)\n }\n}\n","import { startServer } from './server.ts'\n\nexport async function run(_argv?: string[]): Promise<void> {\n await startServer()\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["#emitter","NodeEventEmitter"],"sources":["../package.json","../src/schemas/generateSchema.ts","../../../internals/utils/src/errors.ts","../../../internals/utils/src/asyncEventEmitter.ts","../../../internals/utils/src/promise.ts","../src/types.ts","../src/constants.ts","../src/utils/loadUserConfig.ts","../src/utils/resolveCwd.ts","../src/utils/resolveUserConfig.ts","../src/tools/generate.ts","../src/server.ts","../src/index.ts"],"sourcesContent":["","import { z } from 'zod'\n\nexport const generateSchema = z.object({\n config: z\n .string()\n .optional()\n\n .describe('Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory'),\n input: z.string().optional().describe('Path to OpenAPI/Swagger spec file (overrides config)'),\n output: z.string().optional().describe('Output directory path (overrides config)'),\n logLevel: z.enum(['silent', 'error', 'warn', 'info', 'verbose', 'debug']).optional().default('info').describe('Log level for build output'),\n})\n","/**\n * Thrown when one or more errors occur during a Kubb build.\n * Carries the full list of underlying errors on `errors`.\n *\n * @example\n * ```ts\n * throw new BuildError('Build failed', { errors: [err1, err2] })\n * ```\n */\nexport class BuildError extends Error {\n errors: Array<Error>\n\n constructor(message: string, options: { cause?: Error; errors: Array<Error> }) {\n super(message, { cause: options.cause })\n this.name = 'BuildError'\n this.errors = options.errors\n }\n}\n\n/**\n * Coerces an unknown thrown value to an `Error` instance.\n * Returns the value as-is when it is already an `Error`; otherwise wraps it with `String(value)`.\n *\n * @example\n * ```ts\n * try { ... } catch(err) {\n * throw new BuildError('Build failed', { cause: toError(err), errors: [] })\n * }\n * ```\n */\nexport function toError(value: unknown): Error {\n return value instanceof Error ? value : new Error(String(value))\n}\n\n/**\n * Extracts a human-readable message from any thrown value.\n *\n * @example\n * ```ts\n * getErrorMessage(new Error('oops')) // 'oops'\n * getErrorMessage('plain string') // 'plain string'\n * ```\n */\nexport function getErrorMessage(value: unknown): string {\n return value instanceof Error ? value.message : String(value)\n}\n\n/**\n * Extracts the `.cause` of an `Error` as an `Error`, or `undefined` when absent or not an `Error`.\n *\n * @example\n * ```ts\n * const cause = toCause(buildError) // Error | undefined\n * ```\n */\nexport function toCause(error: Error): Error | undefined {\n return error.cause instanceof Error ? error.cause : undefined\n}\n","import { EventEmitter as NodeEventEmitter } from 'node:events'\nimport { toError } from './errors.ts'\n\n/**\n * A function that can be registered as an event listener, synchronous or async.\n */\ntype AsyncListener<TArgs extends unknown[]> = (...args: TArgs) => void | Promise<void>\n\n/**\n * Typed `EventEmitter` that awaits all async listeners before resolving.\n * Wraps Node's `EventEmitter` with full TypeScript event-map inference.\n *\n * @example\n * ```ts\n * const emitter = new AsyncEventEmitter<{ build: [name: string] }>()\n * emitter.on('build', async (name) => { console.log(name) })\n * await emitter.emit('build', 'petstore') // all listeners awaited\n * ```\n */\nexport class AsyncEventEmitter<TEvents extends { [K in keyof TEvents]: unknown[] }> {\n /**\n * Maximum number of listeners per event before Node emits a memory-leak warning.\n * @default 10\n */\n constructor(maxListener = 10) {\n this.#emitter.setMaxListeners(maxListener)\n }\n\n #emitter = new NodeEventEmitter()\n\n /**\n * Emits `eventName` and awaits all registered listeners sequentially.\n * Throws if any listener rejects, wrapping the cause with the event name and serialized arguments.\n *\n * @example\n * ```ts\n * await emitter.emit('build', 'petstore')\n * ```\n */\n async emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArgs: TEvents[TEventName]): Promise<void> {\n const listeners = this.#emitter.listeners(eventName) as Array<AsyncListener<TEvents[TEventName]>>\n\n if (listeners.length === 0) {\n return\n }\n\n for (const listener of listeners) {\n try {\n await listener(...eventArgs)\n } catch (err) {\n let serializedArgs: string\n try {\n serializedArgs = JSON.stringify(eventArgs)\n } catch {\n serializedArgs = String(eventArgs)\n }\n throw new Error(`Error in async listener for \"${eventName}\" with eventArgs ${serializedArgs}`, { cause: toError(err) })\n }\n }\n }\n\n /**\n * Registers a persistent listener for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', async (name) => { console.log(name) })\n * ```\n */\n on<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.on(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Registers a one-shot listener that removes itself after the first invocation.\n *\n * @example\n * ```ts\n * emitter.onOnce('build', async (name) => { console.log(name) })\n * ```\n */\n onOnce<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n const wrapper: AsyncListener<TEvents[TEventName]> = (...args) => {\n this.off(eventName, wrapper)\n return handler(...args)\n }\n this.on(eventName, wrapper)\n }\n\n /**\n * Removes a previously registered listener.\n *\n * @example\n * ```ts\n * emitter.off('build', handler)\n * ```\n */\n off<TEventName extends keyof TEvents & string>(eventName: TEventName, handler: AsyncListener<TEvents[TEventName]>): void {\n this.#emitter.off(eventName, handler as AsyncListener<unknown[]>)\n }\n\n /**\n * Returns the number of listeners registered for `eventName`.\n *\n * @example\n * ```ts\n * emitter.on('build', handler)\n * emitter.listenerCount('build') // 1\n * ```\n */\n listenerCount<TEventName extends keyof TEvents & string>(eventName: TEventName): number {\n return this.#emitter.listenerCount(eventName)\n }\n\n /**\n * Removes all listeners from every event channel.\n *\n * @example\n * ```ts\n * emitter.removeAll()\n * ```\n */\n removeAll(): void {\n this.#emitter.removeAllListeners()\n }\n}\n","/** A value that may already be resolved or still pending.\n *\n * @example\n * ```ts\n * function load(id: string): PossiblePromise<string> {\n * return cache.get(id) ?? fetchRemote(id)\n * }\n * ```\n */\nexport type PossiblePromise<T> = Promise<T> | T\n\n/** Returns `true` when `result` is a thenable `Promise`.\n *\n * @example\n * ```ts\n * isPromise(Promise.resolve(1)) // true\n * isPromise(42) // false\n * ```\n */\nexport function isPromise<T>(result: PossiblePromise<T>): result is Promise<T> {\n return result !== null && result !== undefined && typeof (result as Record<string, unknown>)['then'] === 'function'\n}\n\n/** Returns `true` when `result` is a fulfilled `Promise.allSettled` result.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseFulfilledResult).map((r) => r.value)\n * ```\n */\nexport function isPromiseFulfilledResult<T = unknown>(result: PromiseSettledResult<unknown>): result is PromiseFulfilledResult<T> {\n return result.status === 'fulfilled'\n}\n\n/** Returns `true` when `result` is a rejected `Promise.allSettled` result with a typed `reason`.\n *\n * @example\n * ```ts\n * const results = await Promise.allSettled([p1, p2])\n * results.filter(isPromiseRejectedResult<Error>).map((r) => r.reason.message)\n * ```\n */\nexport function isPromiseRejectedResult<T>(result: PromiseSettledResult<unknown>): result is Omit<PromiseRejectedResult, 'reason'> & { reason: T } {\n return result.status === 'rejected'\n}\n","export const NotifyTypes = {\n INFO: 'INFO',\n SUCCESS: 'SUCCESS',\n ERROR: 'ERROR',\n WARN: 'WARN',\n PLUGIN_START: 'PLUGIN_START',\n PLUGIN_END: 'PLUGIN_END',\n FILES_START: 'FILES_START',\n FILE_UPDATE: 'FILE_UPDATE',\n FILES_END: 'FILES_END',\n GENERATION_START: 'GENERATION_START',\n GENERATION_END: 'GENERATION_END',\n CONFIG_LOADED: 'CONFIG_LOADED',\n CONFIG_ERROR: 'CONFIG_ERROR',\n CONFIG_READY: 'CONFIG_READY',\n SETUP_START: 'SETUP_START',\n SETUP_END: 'SETUP_END',\n BUILD_START: 'BUILD_START',\n BUILD_END: 'BUILD_END',\n BUILD_FAILED: 'BUILD_FAILED',\n BUILD_SUCCESS: 'BUILD_SUCCESS',\n FATAL_ERROR: 'FATAL_ERROR',\n} as const\n","export const ALLOWED_CONFIG_EXTENSIONS = new Set(['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'])\n","import { existsSync } from 'node:fs'\nimport path from 'node:path'\nimport type { Config } from '@kubb/core'\nimport { unrun } from 'unrun'\nimport { ALLOWED_CONFIG_EXTENSIONS } from '../constants.ts'\nimport { NotifyTypes } from '../types.ts'\n\ntype NotifyFunction = (type: string, message: string, data?: Record<string, unknown>) => Promise<void>\n\nconst loadedModules = new Map<string, unknown>()\n\nasync function loadModule(filePath: string): Promise<unknown> {\n const ext = path.extname(filePath)\n if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {\n throw new Error(`Invalid config file extension \"${ext}\". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`)\n }\n if (loadedModules.has(filePath)) {\n return loadedModules.get(filePath)\n }\n const { module } = await unrun({ path: filePath })\n loadedModules.set(filePath, module)\n return module\n}\n\nexport async function loadUserConfig(configPath: string | undefined, { notify }: { notify: NotifyFunction }): Promise<{ userConfig: Config; cwd: string }> {\n let userConfig: Config | undefined\n let cwd: string\n\n if (configPath) {\n const ext = path.extname(configPath)\n if (!ALLOWED_CONFIG_EXTENSIONS.has(ext)) {\n const msg = `Invalid config file extension \"${ext}\". Allowed: ${[...ALLOWED_CONFIG_EXTENSIONS].join(', ')}`\n await notify(NotifyTypes.CONFIG_ERROR, msg)\n throw new Error(msg)\n }\n const base = path.resolve(process.cwd())\n const resolvedConfigPath = path.resolve(base, configPath)\n const relative = path.relative(base, resolvedConfigPath)\n if (relative.startsWith('..') || path.isAbsolute(relative)) {\n const msg = 'Invalid config file path: must be within the current working directory'\n await notify(NotifyTypes.CONFIG_ERROR, msg)\n throw new Error(msg)\n }\n cwd = path.dirname(resolvedConfigPath)\n\n try {\n userConfig = (await loadModule(resolvedConfigPath)) as Config\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${resolvedConfigPath}`)\n } catch (error) {\n await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`)\n }\n } else {\n cwd = process.cwd()\n const configFileNames = ['kubb.config.ts', 'kubb.config.mts', 'kubb.config.cts', 'kubb.config.js', 'kubb.config.cjs']\n\n for (const configFileName of configFileNames) {\n const configFilePath = path.resolve(process.cwd(), configFileName)\n if (!existsSync(configFilePath)) continue\n try {\n userConfig = (await loadModule(configFilePath)) as Config\n await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`)\n break\n } catch {\n // Continue trying next config file\n }\n }\n\n if (!userConfig) {\n await notify(NotifyTypes.CONFIG_ERROR, 'No config file found')\n\n throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(', ')}`)\n }\n }\n\n return { userConfig: userConfig!, cwd }\n}\n","import path from 'node:path'\nimport type { Config } from '@kubb/core'\n\n/**\n * Determine the root directory based on userConfig.root and resolvedConfigDir\n * 1. If userConfig.root exists and is absolute, use it as-is\n * 2. If userConfig.root exists and is relative, resolve it relative to config directory\n * 3. Otherwise, use the config directory as root\n */\nexport function resolveCwd(userConfig: Config, cwd: string): string {\n if (userConfig.root) {\n if (path.isAbsolute(userConfig.root)) {\n return userConfig.root\n }\n\n return path.resolve(cwd, userConfig.root)\n }\n\n return cwd\n}\n","import { isPromise } from '@internals/utils'\nimport type { CLIOptions, Config } from '@kubb/core'\n\nexport type ResolveUserConfigOptions = {\n configPath?: string\n logLevel?: string\n}\n\n/**\n * Resolve the config by handling function configs and returning the final configuration\n */\nexport async function resolveUserConfig(config: Config, options: ResolveUserConfigOptions): Promise<Config> {\n let kubbUserConfig = Promise.resolve(config) as Promise<Config>\n\n if (typeof config === 'function') {\n const possiblePromise = (config as any)({\n logLevel: options.logLevel,\n config: options.configPath,\n } as CLIOptions)\n if (isPromise(possiblePromise)) {\n kubbUserConfig = possiblePromise\n } else {\n kubbUserConfig = Promise.resolve(possiblePromise)\n }\n }\n\n return (await kubbUserConfig) as Config\n}\n","import { AsyncEventEmitter } from '@internals/utils'\nimport { type Config, createKubb, type KubbHooks } from '@kubb/core'\nimport type { CallToolResult } from '@modelcontextprotocol/sdk/types.d.ts'\nimport type { z } from 'zod'\nimport type { generateSchema } from '../schemas/generateSchema.ts'\nimport { NotifyTypes } from '../types.ts'\nimport { loadUserConfig } from '../utils/loadUserConfig.ts'\nimport { resolveCwd } from '../utils/resolveCwd.ts'\nimport { resolveUserConfig } from '../utils/resolveUserConfig.ts'\n\ninterface NotificationHandler {\n sendNotification(method: string, params: unknown): Promise<void>\n}\n\n/**\n * Build tool that generates code from OpenAPI specs using Kubb.\n * Sends real-time notifications of build progress and events.\n */\nexport async function generate(schema: z.infer<typeof generateSchema>, handler: NotificationHandler): Promise<CallToolResult> {\n const { config: configPath, input, output, logLevel } = schema\n\n try {\n const hooks = new AsyncEventEmitter<KubbHooks>()\n const messages: string[] = []\n\n // Helper to send notifications\n const notify = async (type: string, message: string, data?: Record<string, unknown>) => {\n messages.push(`${type}: ${message}`)\n\n await handler.sendNotification('kubb/progress', {\n type,\n message,\n timestamp: new Date().toISOString(),\n ...data,\n })\n }\n\n // Capture events for output and send notifications\n hooks.on('kubb:info', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.INFO, message)\n })\n\n hooks.on('kubb:success', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.SUCCESS, message)\n })\n\n hooks.on('kubb:error', async ({ error }: { error: Error }) => {\n await notify(NotifyTypes.ERROR, error.message, { stack: error.stack })\n })\n\n hooks.on('kubb:warn', async ({ message }: { message: string }) => {\n await notify(NotifyTypes.WARN, message)\n })\n\n // Plugin lifecycle events\n hooks.on('kubb:plugin:start', async ({ plugin }) => {\n await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${plugin.name}`)\n })\n\n hooks.on('kubb:plugin:end', async ({ plugin, duration }) => {\n await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${plugin.name}`, {\n duration,\n })\n })\n\n // File processing events\n hooks.on('kubb:files:processing:start', async () => {\n await notify(NotifyTypes.FILES_START, 'Starting file processing')\n })\n\n hooks.on('kubb:file:processing:update', async ({ file }: { file: { name: string } }) => {\n await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`)\n })\n\n hooks.on('kubb:files:processing:end', async () => {\n await notify(NotifyTypes.FILES_END, 'File processing complete')\n })\n\n // Generation events\n hooks.on('kubb:generation:start', async () => {\n await notify(NotifyTypes.GENERATION_START, 'Generation started')\n })\n\n hooks.on('kubb:generation:end', async () => {\n await notify(NotifyTypes.GENERATION_END, 'Generation ended')\n })\n\n // Load and process configuration\n let userConfig: Config\n let cwd: string\n\n try {\n const configResult = await loadUserConfig(configPath, { notify })\n userConfig = configResult.userConfig\n cwd = configResult.cwd\n\n if (Array.isArray(userConfig) && userConfig.length) {\n throw new Error('Array type in kubb.config.ts is not supported in this tool. Please provide a single configuration object.')\n }\n\n userConfig = await resolveUserConfig(userConfig, {\n configPath,\n logLevel,\n })\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n await notify(NotifyTypes.CONFIG_ERROR, errorMessage)\n return {\n content: [\n {\n type: 'text',\n text: errorMessage,\n },\n ],\n isError: true,\n }\n }\n\n const inputPath = input ?? ('path' in userConfig.input ? userConfig.input.path : undefined)\n\n // Override config with CLI options\n const config: Config = {\n ...userConfig,\n root: resolveCwd(userConfig, cwd),\n input: inputPath\n ? {\n ...userConfig.input,\n path: inputPath,\n }\n : userConfig.input,\n output: output\n ? {\n ...userConfig.output,\n path: output,\n }\n : userConfig.output,\n }\n\n await notify(NotifyTypes.CONFIG_READY, 'Configuration ready', {\n root: config.root,\n })\n\n // Setup and build\n await notify(NotifyTypes.SETUP_START, 'Setting up Kubb')\n\n const kubb = createKubb(config, { hooks })\n await kubb.setup()\n await notify(NotifyTypes.SETUP_END, 'Kubb setup complete')\n\n await notify(NotifyTypes.BUILD_START, 'Starting build')\n const { files, failedPlugins, error } = await kubb.safeBuild()\n await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`)\n\n if (error || failedPlugins.size > 0) {\n const allErrors: Error[] = [\n error,\n ...Array.from(failedPlugins)\n .filter((it) => it.error)\n .map((it) => it.error),\n ].filter(Boolean)\n\n await notify(NotifyTypes.BUILD_FAILED, `Build failed with ${allErrors.length} error(s)`, {\n errorCount: allErrors.length,\n errors: allErrors.map((err) => err.message),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build failed:\\n${allErrors.map((err) => err.message).join('\\n')}\\n\\n${messages.join('\\n')}`,\n },\n ],\n isError: true,\n }\n }\n\n await notify(NotifyTypes.BUILD_SUCCESS, `Build completed successfully - Generated ${files.length} files`, {\n filesCount: files.length,\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build completed successfully!\\n\\nGenerated ${files.length} files\\n\\n${messages.join('\\n')}`,\n },\n ],\n }\n } catch (caughtError) {\n const error = caughtError as Error\n\n await handler.sendNotification('kubb/progress', {\n type: NotifyTypes.FATAL_ERROR,\n message: error.message,\n stack: error.stack,\n timestamp: new Date().toISOString(),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Build error: ${error.message}\\n${error.stack || ''}`,\n },\n ],\n isError: true,\n }\n }\n}\n","import process from 'node:process'\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'\nimport { version } from '../package.json'\nimport { generateSchema } from './schemas/generateSchema.ts'\nimport { generate } from './tools/generate.ts'\n\n/**\n * Kubb MCP Server\n *\n * Provides tools for building OpenAPI specifications using Kubb.\n */\nexport async function startServer() {\n try {\n const transport = new StdioServerTransport()\n const server = new McpServer({\n name: 'Kubb',\n version,\n })\n\n // Build tool - runs Kubb build using @kubb/core\n // Wrapped to pass notification handler for real-time progress updates\n server.tool('generate', 'Generate OpenAPI spec helpers using Kubb configuration', generateSchema.shape, async (args) => {\n // Create notification handler that sends events back to the client\n const notificationHandler = {\n sendNotification: async (method: string, params: any) => {\n try {\n await transport.send({\n jsonrpc: '2.0',\n method,\n params,\n })\n } catch (error) {\n console.error('Failed to send notification:', error)\n }\n },\n }\n\n // Call build tool with notification handler\n return generate(args, notificationHandler)\n })\n\n await server.connect(transport)\n } catch (error) {\n console.error('Failed to start MCP server:', error)\n process.exit(1)\n }\n}\n","import { startServer } from './server.ts'\n\nexport async function run(_argv?: string[]): Promise<void> {\n await startServer()\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,36 +1,26 @@
1
1
  {
2
2
  "name": "@kubb/mcp",
3
- "version": "5.0.0-alpha.8",
3
+ "version": "5.0.0-beta.1",
4
4
  "description": "Model Context Protocol (MCP) server for Kubb, enabling AI assistants to generate code from OpenAPI specifications.",
5
5
  "keywords": [
6
- "mcp",
7
- "model-context-protocol",
8
6
  "ai",
9
- "llm",
10
7
  "code-generation",
8
+ "codegen",
9
+ "kubb",
10
+ "llm",
11
+ "mcp",
12
+ "model-context-protocol",
11
13
  "openapi",
12
14
  "swagger",
13
- "typescript",
14
- "codegen",
15
- "kubb"
15
+ "typescript"
16
16
  ],
17
+ "license": "MIT",
18
+ "author": "stijnvanhulle",
17
19
  "repository": {
18
20
  "type": "git",
19
21
  "url": "git+https://github.com/kubb-labs/kubb.git",
20
22
  "directory": "packages/mcp"
21
23
  },
22
- "license": "MIT",
23
- "author": "stijnvanhulle",
24
- "sideEffects": false,
25
- "type": "module",
26
- "exports": {
27
- ".": {
28
- "import": "./dist/index.js",
29
- "require": "./dist/index.cjs"
30
- },
31
- "./package.json": "./package.json"
32
- },
33
- "types": "./dist/index.d.ts",
34
24
  "bin": {
35
25
  "kubb-mcp": "bin/kubb-mcp.cjs"
36
26
  },
@@ -42,6 +32,35 @@
42
32
  "!/**/__tests__/**",
43
33
  "!/**/__snapshots__/**"
44
34
  ],
35
+ "type": "module",
36
+ "sideEffects": false,
37
+ "main": "./dist/index.cjs",
38
+ "module": "./dist/index.js",
39
+ "types": "./dist/index.d.ts",
40
+ "exports": {
41
+ ".": {
42
+ "import": "./dist/index.js",
43
+ "require": "./dist/index.cjs"
44
+ },
45
+ "./package.json": "./package.json"
46
+ },
47
+ "publishConfig": {
48
+ "access": "public",
49
+ "registry": "https://registry.npmjs.org/"
50
+ },
51
+ "dependencies": {
52
+ "@modelcontextprotocol/sdk": "^1.29.0",
53
+ "unrun": "^0.2.37",
54
+ "zod": "^4.3.6",
55
+ "@kubb/core": "5.0.0-beta.1"
56
+ },
57
+ "devDependencies": {
58
+ "@internals/utils": "0.0.0",
59
+ "@kubb/renderer-jsx": "5.0.0-beta.1"
60
+ },
61
+ "peerDependencies": {
62
+ "@kubb/renderer-jsx": "5.0.0-beta.1"
63
+ },
45
64
  "size-limit": [
46
65
  {
47
66
  "path": "./dist/*.js",
@@ -49,37 +68,16 @@
49
68
  "gzip": true
50
69
  }
51
70
  ],
52
- "dependencies": {
53
- "@kubb/fabric-core": "0.14.0",
54
- "@kubb/react-fabric": "0.14.0",
55
- "@modelcontextprotocol/sdk": "^1.27.1",
56
- "jiti": "2.5.1",
57
- "zod": "^4.3.6",
58
- "@kubb/core": "5.0.0-alpha.8"
59
- },
60
- "peerDependencies": {
61
- "@kubb/fabric-core": "0.14.0",
62
- "@kubb/react-fabric": "0.14.0"
63
- },
64
71
  "engines": {
65
72
  "node": ">=22"
66
73
  },
67
- "publishConfig": {
68
- "access": "public",
69
- "registry": "https://registry.npmjs.org/"
70
- },
71
- "main": "./dist/index.cjs",
72
- "module": "./dist/index.js",
73
- "devDependencies": {
74
- "@internals/utils": "0.0.0"
75
- },
76
74
  "scripts": {
77
75
  "build": "tsdown && size-limit",
78
76
  "start:mcp": "bun --watch ./src/server.ts",
79
77
  "debug:mcp": "npx -y @modelcontextprotocol/inspector node ./bin/kubb-mcp.cjs",
80
78
  "clean": "npx rimraf ./dist",
81
- "lint": "bun biome lint .",
82
- "lint:fix": "bun biome lint --fix --unsafe .",
79
+ "lint": "oxlint .",
80
+ "lint:fix": "oxlint --fix .",
83
81
  "release": "pnpm publish --no-git-check",
84
82
  "release:canary": "bash ../../.github/canary.sh && node ../../scripts/build.js canary && pnpm publish --no-git-check",
85
83
  "start": "tsdown --watch",
@@ -0,0 +1 @@
1
+ export const ALLOWED_CONFIG_EXTENSIONS = new Set(['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'])
@@ -10,4 +10,3 @@ export const generateSchema = z.object({
10
10
  output: z.string().optional().describe('Output directory path (overrides config)'),
11
11
  logLevel: z.enum(['silent', 'error', 'warn', 'info', 'verbose', 'debug']).optional().default('info').describe('Log level for build output'),
12
12
  })
13
-