@kubb/mcp 4.15.2 → 4.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # @kubb/mcp
2
+
3
+ Model Context Protocol (MCP) server for Kubb.
4
+
5
+ ## Overview
6
+
7
+ This package provides an MCP server that exposes Kubb's code generation functionality through the [Model Context Protocol](https://modelcontextprotocol.io), allowing AI assistants like [Claude](https://claude.ai), [Cursor](https://cursor.sh), and other MCP-compatible clients to generate code from OpenAPI specifications using natural language.
8
+
9
+ The server acts as a bridge between MCP clients (like [Claude Desktop](https://claude.ai/download)) and Kubb's build system, enabling conversational code generation workflows.
10
+
11
+ ## Features
12
+
13
+ - **Generate Tool**: Generate TypeScript types, API clients, and more from OpenAPI specs using your `kubb.config.ts`
14
+ - **Real-time Progress Notifications**: Stream build events and progress updates to the MCP client
15
+ - Uses `@kubb/core` build functionality directly
16
+ - Lightweight and focused on code generation
17
+
18
+ ## Installation
19
+
20
+ Install as a dev dependency:
21
+
22
+ ```bash [npm]
23
+ npm install --save-dev @kubb/mcp
24
+ ```
25
+
26
+ > [!IMPORTANT]
27
+ > You also need to install `@kubb/cli` to use the `kubb mcp` command.
28
+
29
+ ## Usage
30
+
31
+ ### Start the MCP Server
32
+
33
+ Start the server using the Kubb CLI:
34
+
35
+ ```bash
36
+ npx kubb mcp
37
+ ```
38
+
39
+ Or run it directly as a standalone package:
40
+
41
+ ```bash
42
+ npx @kubb/mcp
43
+ ```
44
+
45
+ This starts an MCP server that communicates via stdio (standard input/output), making it compatible with MCP clients.
46
+
47
+ ### Configure MCP Client
48
+
49
+ Add to your MCP client configuration (e.g., [Claude Desktop](https://claude.ai/download)'s `claude_desktop_config.json`):
50
+
51
+ **Option 1: Using Kubb CLI (recommended):**
52
+ ```json
53
+ {
54
+ "mcpServers": {
55
+ "kubb": {
56
+ "command": "npx",
57
+ "args": ["kubb", "mcp"]
58
+ }
59
+ }
60
+ }
61
+ ```
62
+
63
+ **Option 2: Using standalone bin:**
64
+ ```json
65
+ {
66
+ "mcpServers": {
67
+ "kubb": {
68
+ "command": "npx",
69
+ "args": ["@kubb/mcp"]
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ For project-specific configurations, you can specify the working directory:
76
+
77
+ ```json
78
+ {
79
+ "mcpServers": {
80
+ "kubb-petstore": {
81
+ "command": "npx",
82
+ "args": ["@kubb/mcp"],
83
+ "cwd": "/path/to/your/project"
84
+ }
85
+ }
86
+ }
87
+ ```
88
+
89
+ ### Available Tools
90
+
91
+ #### `generate`
92
+
93
+ Generate code from OpenAPI/Swagger specifications using Kubb configuration.
94
+
95
+ **Parameters:**
96
+ - `config` (string, optional): Path to kubb.config.ts file. If not provided, looks for kubb.config.ts in current directory
97
+ - `input` (string, optional): Path to OpenAPI/Swagger spec file (overrides config file setting)
98
+ - `output` (string, optional): Output directory path (overrides config file setting)
99
+ - `logLevel` (enum, optional): Control logging verbosity - `'silent'`, `'error'`, `'warn'`, `'info'`, `'verbose'`, `'debug'` (default: 'info')
100
+
101
+ **Examples:**
102
+
103
+ Using default config file:
104
+ ```json
105
+ {
106
+ "config": "./kubb.config.ts"
107
+ }
108
+ ```
109
+
110
+ Overriding input and output:
111
+ ```json
112
+ {
113
+ "config": "./kubb.config.ts",
114
+ "input": "./specs/petstore.yaml",
115
+ "output": "./src/generated"
116
+ }
117
+ ```
118
+
119
+ With verbose logging:
120
+ ```json
121
+ {
122
+ "config": "./kubb.config.ts",
123
+ "logLevel": "verbose"
124
+ }
125
+ ```
126
+
127
+ ## Configuration
128
+
129
+ The build tool looks for `kubb.config.ts` in the current directory by default. You can also provide an inline configuration or path to a config file.
130
+
131
+ Example `kubb.config.ts`:
132
+
133
+ ```typescript
134
+ import { defineConfig } from '@kubb/core'
135
+ import { pluginOas } from '@kubb/plugin-oas'
136
+ import { pluginTs } from '@kubb/plugin-ts'
137
+ import { pluginClient } from '@kubb/plugin-client'
138
+
139
+ export default defineConfig({
140
+ input: {
141
+ path: './petstore.yaml',
142
+ },
143
+ output: {
144
+ path: './src/generated',
145
+ },
146
+ plugins: [
147
+ pluginOas(),
148
+ pluginTs(),
149
+ pluginClient(),
150
+ ],
151
+ })
152
+ ```
153
+
154
+ ## License
155
+
156
+ MIT
157
+
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+
3
+ import('../dist/index.js')
4
+ .then(({ run }) => {
5
+ process.title = 'Kubb MCP'
6
+ run(process.argv)
7
+ })
8
+ .catch((err) => {
9
+ console.error('Failed to start Kubb MCP server:', err)
10
+ process.exit(1)
11
+ })
package/dist/index.cjs CHANGED
@@ -1,3 +1,345 @@
1
- const require_src = require('./src-C8Z8ptbx.cjs');
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") {
10
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) {
13
+ __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ }
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
2
26
 
3
- exports.startServer = require_src.startServer;
27
+ //#endregion
28
+ let node_process = require("node:process");
29
+ node_process = __toESM(node_process);
30
+ let _modelcontextprotocol_sdk_server_mcp_js = require("@modelcontextprotocol/sdk/server/mcp.js");
31
+ let _modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
32
+ let zod = require("zod");
33
+ let _kubb_core = require("@kubb/core");
34
+ let _kubb_core_utils = require("@kubb/core/utils");
35
+ let node_path = require("node:path");
36
+ node_path = __toESM(node_path);
37
+ let jiti = require("jiti");
38
+ jiti = __toESM(jiti);
39
+
40
+ //#region package.json
41
+ var version = "4.17.0";
42
+
43
+ //#endregion
44
+ //#region src/schemas/generateSchema.ts
45
+ const generateSchema = zod.z.object({
46
+ config: zod.z.string().optional().describe("Path to kubb.config file (supports .ts, .js, .cjs). If not provided, will look for kubb.config.{ts,js,cjs} in current directory"),
47
+ input: zod.z.string().optional().describe("Path to OpenAPI/Swagger spec file (overrides config)"),
48
+ output: zod.z.string().optional().describe("Output directory path (overrides config)"),
49
+ logLevel: zod.z.enum([
50
+ "silent",
51
+ "error",
52
+ "warn",
53
+ "info",
54
+ "verbose",
55
+ "debug"
56
+ ]).optional().default("info").describe("Log level for build output")
57
+ });
58
+
59
+ //#endregion
60
+ //#region src/types.ts
61
+ const NotifyTypes = {
62
+ INFO: "INFO",
63
+ SUCCESS: "SUCCESS",
64
+ ERROR: "ERROR",
65
+ WARN: "WARN",
66
+ PLUGIN_START: "PLUGIN_START",
67
+ PLUGIN_END: "PLUGIN_END",
68
+ FILES_START: "FILES_START",
69
+ FILE_UPDATE: "FILE_UPDATE",
70
+ FILES_END: "FILES_END",
71
+ GENERATION_START: "GENERATION_START",
72
+ GENERATION_END: "GENERATION_END",
73
+ CONFIG_LOADED: "CONFIG_LOADED",
74
+ CONFIG_ERROR: "CONFIG_ERROR",
75
+ CONFIG_READY: "CONFIG_READY",
76
+ SETUP_START: "SETUP_START",
77
+ SETUP_END: "SETUP_END",
78
+ BUILD_START: "BUILD_START",
79
+ BUILD_END: "BUILD_END",
80
+ BUILD_FAILED: "BUILD_FAILED",
81
+ BUILD_SUCCESS: "BUILD_SUCCESS",
82
+ FATAL_ERROR: "FATAL_ERROR"
83
+ };
84
+
85
+ //#endregion
86
+ //#region src/utils/loadUserConfig.ts
87
+ const jiti$1 = (0, jiti.default)(require("url").pathToFileURL(__filename).href, { sourceMaps: true });
88
+ /**
89
+ * Load the user configuration from the specified path or current directory
90
+ */
91
+ async function loadUserConfig(configPath, { notify }) {
92
+ let userConfig;
93
+ let cwd;
94
+ if (configPath) {
95
+ cwd = node_path.default.dirname(node_path.default.resolve(configPath));
96
+ try {
97
+ userConfig = await jiti$1.import(configPath, { default: true });
98
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded config from ${configPath}`);
99
+ } catch (error) {
100
+ await notify(NotifyTypes.CONFIG_ERROR, `Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
101
+ throw new Error(`Failed to load config: ${error instanceof Error ? error.message : String(error)}`);
102
+ }
103
+ } else {
104
+ cwd = process.cwd();
105
+ const configFileNames = [
106
+ "kubb.config.ts",
107
+ "kubb.config.js",
108
+ "kubb.config.cjs"
109
+ ];
110
+ for (const configFileName of configFileNames) try {
111
+ const configFilePath = node_path.default.resolve(process.cwd(), configFileName);
112
+ userConfig = await jiti$1.import(configFilePath, { default: true });
113
+ await notify(NotifyTypes.CONFIG_LOADED, `Loaded ${configFileName} from current directory`);
114
+ break;
115
+ } catch {}
116
+ if (!userConfig) {
117
+ await notify(NotifyTypes.CONFIG_ERROR, "No config file found");
118
+ throw new Error(`No config file found. Please provide a config path or create one of: ${configFileNames.join(", ")}`);
119
+ }
120
+ }
121
+ return {
122
+ userConfig,
123
+ cwd
124
+ };
125
+ }
126
+
127
+ //#endregion
128
+ //#region src/utils/resolveCwd.ts
129
+ /**
130
+ * Determine the root directory based on userConfig.root and resolvedConfigDir
131
+ * 1. If userConfig.root exists and is absolute, use it as-is
132
+ * 2. If userConfig.root exists and is relative, resolve it relative to config directory
133
+ * 3. Otherwise, use the config directory as root
134
+ */
135
+ function resolveCwd(userConfig, cwd) {
136
+ if (userConfig.root) {
137
+ if (node_path.default.isAbsolute(userConfig.root)) return userConfig.root;
138
+ return node_path.default.resolve(cwd, userConfig.root);
139
+ }
140
+ return cwd;
141
+ }
142
+
143
+ //#endregion
144
+ //#region src/utils/resolveUserConfig.ts
145
+ /**
146
+ * Resolve the config by handling function configs and returning the final configuration
147
+ */
148
+ async function resolveUserConfig(userConfig, options) {
149
+ let kubbUserConfig = Promise.resolve(userConfig);
150
+ if (typeof userConfig === "function") {
151
+ const possiblePromise = userConfig({
152
+ logLevel: options.logLevel,
153
+ config: options.configPath
154
+ });
155
+ if ((0, _kubb_core_utils.isPromise)(possiblePromise)) kubbUserConfig = possiblePromise;
156
+ else kubbUserConfig = Promise.resolve(possiblePromise);
157
+ }
158
+ return await kubbUserConfig;
159
+ }
160
+
161
+ //#endregion
162
+ //#region src/tools/generate.ts
163
+ /**
164
+ * Build tool that generates code from OpenAPI specs using Kubb.
165
+ * Sends real-time notifications of build progress and events.
166
+ */
167
+ async function generate(schema, handler) {
168
+ const { config: configPath, input, output, logLevel } = schema;
169
+ try {
170
+ const events = new _kubb_core_utils.AsyncEventEmitter();
171
+ const messages = [];
172
+ const notify = async (type, message, data) => {
173
+ messages.push(`${type}: ${message}`);
174
+ await handler.sendNotification("kubb/progress", {
175
+ type,
176
+ message,
177
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
178
+ ...data
179
+ });
180
+ };
181
+ events.on("info", async (message) => {
182
+ await notify(NotifyTypes.INFO, message);
183
+ });
184
+ events.on("success", async (message) => {
185
+ await notify(NotifyTypes.SUCCESS, message);
186
+ });
187
+ events.on("error", async (error$1) => {
188
+ await notify(NotifyTypes.ERROR, error$1.message, { stack: error$1.stack });
189
+ });
190
+ events.on("warn", async (message) => {
191
+ await notify(NotifyTypes.WARN, message);
192
+ });
193
+ events.on("plugin:start", async ({ name }) => {
194
+ await notify(NotifyTypes.PLUGIN_START, `Plugin starting: ${name}`);
195
+ });
196
+ events.on("plugin:end", async ({ name, duration }) => {
197
+ await notify(NotifyTypes.PLUGIN_END, `Plugin finished: ${name}`, { duration });
198
+ });
199
+ events.on("files:processing:start", async () => {
200
+ await notify(NotifyTypes.FILES_START, "Starting file processing");
201
+ });
202
+ events.on("file:processing:update", async ({ file }) => {
203
+ await notify(NotifyTypes.FILE_UPDATE, `Processing file: ${file.name}`);
204
+ });
205
+ events.on("files:processing:end", async () => {
206
+ await notify(NotifyTypes.FILES_END, "File processing complete");
207
+ });
208
+ events.on("generation:start", async () => {
209
+ await notify(NotifyTypes.GENERATION_START, "Generation started");
210
+ });
211
+ events.on("generation:end", async () => {
212
+ await notify(NotifyTypes.GENERATION_END, "Generation ended");
213
+ });
214
+ let userConfig;
215
+ let cwd;
216
+ try {
217
+ const configResult = await loadUserConfig(configPath, { notify });
218
+ userConfig = configResult.userConfig;
219
+ cwd = configResult.cwd;
220
+ if (Array.isArray(userConfig) && userConfig.length) throw new Error("Array type in kubb.config.ts is not supported in this tool. Please provide a single configuration object.");
221
+ userConfig = await resolveUserConfig(userConfig, {
222
+ configPath,
223
+ logLevel
224
+ });
225
+ } catch (error$1) {
226
+ const errorMessage = error$1 instanceof Error ? error$1.message : String(error$1);
227
+ await notify(NotifyTypes.CONFIG_ERROR, errorMessage);
228
+ return {
229
+ content: [{
230
+ type: "text",
231
+ text: errorMessage
232
+ }],
233
+ isError: true
234
+ };
235
+ }
236
+ const inputPath = input ?? ("path" in userConfig.input ? userConfig.input.path : void 0);
237
+ const config = {
238
+ ...userConfig,
239
+ root: resolveCwd(userConfig, cwd),
240
+ input: inputPath ? {
241
+ ...userConfig.input,
242
+ path: inputPath
243
+ } : userConfig.input,
244
+ output: output ? {
245
+ ...userConfig.output,
246
+ path: output
247
+ } : userConfig.output
248
+ };
249
+ await notify(NotifyTypes.CONFIG_READY, "Configuration ready", { root: config.root });
250
+ await notify(NotifyTypes.SETUP_START, "Setting up Kubb");
251
+ const { fabric, pluginManager } = await (0, _kubb_core.setup)({
252
+ config,
253
+ events
254
+ });
255
+ await notify(NotifyTypes.SETUP_END, "Kubb setup complete");
256
+ await notify(NotifyTypes.BUILD_START, "Starting build");
257
+ const { files, failedPlugins, error } = await (0, _kubb_core.safeBuild)({
258
+ config,
259
+ events
260
+ }, {
261
+ pluginManager,
262
+ fabric,
263
+ events
264
+ });
265
+ await notify(NotifyTypes.BUILD_END, `Build complete - Generated ${files.length} files`);
266
+ if (error || failedPlugins.size > 0) {
267
+ const allErrors = [error, ...Array.from(failedPlugins).filter((it) => it.error).map((it) => it.error)].filter(Boolean);
268
+ await notify(NotifyTypes.BUILD_FAILED, `Build failed with ${allErrors.length} error(s)`, {
269
+ errorCount: allErrors.length,
270
+ errors: allErrors.map((err) => err.message)
271
+ });
272
+ return {
273
+ content: [{
274
+ type: "text",
275
+ text: `Build failed:\n${allErrors.map((err) => err.message).join("\n")}\n\n${messages.join("\n")}`
276
+ }],
277
+ isError: true
278
+ };
279
+ }
280
+ await notify(NotifyTypes.BUILD_SUCCESS, `Build completed successfully - Generated ${files.length} files`, { filesCount: files.length });
281
+ return { content: [{
282
+ type: "text",
283
+ text: `Build completed successfully!\n\nGenerated ${files.length} files\n\n${messages.join("\n")}`
284
+ }] };
285
+ } catch (caughtError) {
286
+ const error = caughtError;
287
+ await handler.sendNotification("kubb/progress", {
288
+ type: NotifyTypes.FATAL_ERROR,
289
+ message: error.message,
290
+ stack: error.stack,
291
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
292
+ });
293
+ return {
294
+ content: [{
295
+ type: "text",
296
+ text: `Build error: ${error.message}\n${error.stack || ""}`
297
+ }],
298
+ isError: true
299
+ };
300
+ }
301
+ }
302
+
303
+ //#endregion
304
+ //#region src/server.ts
305
+ /**
306
+ * Kubb MCP Server
307
+ *
308
+ * Provides tools for building OpenAPI specifications using Kubb.
309
+ */
310
+ async function startServer() {
311
+ try {
312
+ const transport = new _modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport();
313
+ const server = new _modelcontextprotocol_sdk_server_mcp_js.McpServer({
314
+ name: "Kubb",
315
+ version
316
+ });
317
+ server.tool("generate", "Generate OpenAPI spec helpers using Kubb configuration", generateSchema.shape, async (args) => {
318
+ return generate(args, { sendNotification: async (method, params) => {
319
+ try {
320
+ await transport.send({
321
+ jsonrpc: "2.0",
322
+ method,
323
+ params
324
+ });
325
+ } catch (error) {
326
+ console.error("Failed to send notification:", error);
327
+ }
328
+ } });
329
+ });
330
+ await server.connect(transport);
331
+ } catch (error) {
332
+ console.error("Failed to start MCP server:", error);
333
+ node_process.default.exit(1);
334
+ }
335
+ }
336
+
337
+ //#endregion
338
+ //#region src/index.ts
339
+ async function run(_argv) {
340
+ await startServer();
341
+ }
342
+
343
+ //#endregion
344
+ exports.run = run;
345
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["z","jiti","userConfig: Config | undefined","cwd: string","path","path","AsyncEventEmitter","messages: string[]","error","userConfig: Config","cwd: string","config: Config","allErrors: Error[]","StdioServerTransport","McpServer"],"sources":["../package.json","../src/schemas/generateSchema.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","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 type { CLIOptions, Config, UserConfig } from '@kubb/core'\nimport { isPromise } from '@kubb/core/utils'\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 { type Config, type KubbEvents, safeBuild, setup } from '@kubb/core'\nimport { AsyncEventEmitter } from '@kubb/core/utils'\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, pluginManager } = 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 { pluginManager, fabric, events },\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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"}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region src/index.d.ts
2
- declare function startServer(): Promise<void>;
2
+ declare function run(_argv?: string[]): Promise<void>;
3
3
  //#endregion
4
- export { startServer };
4
+ export { run };
5
5
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region src/index.d.ts
2
- declare function startServer(): Promise<void>;
2
+ declare function run(_argv?: string[]): Promise<void>;
3
3
  //#endregion
4
- export { startServer };
4
+ export { run };
5
5
  //# sourceMappingURL=index.d.ts.map