@kubb/plugin-mcp 5.0.0-beta.4 → 5.0.0-beta.42
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 +39 -22
- package/dist/index.cjs +343 -205
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +82 -27
- package/dist/index.js +345 -207
- package/dist/index.js.map +1 -1
- package/extension.yaml +633 -160
- package/package.json +11 -11
- package/src/components/McpHandler.tsx +15 -20
- package/src/components/Server.tsx +76 -71
- package/src/generators/mcpGenerator.tsx +21 -23
- package/src/generators/serverGenerator.tsx +22 -22
- package/src/plugin.ts +38 -18
- package/src/resolvers/resolverMcp.ts +16 -6
- package/src/types.ts +27 -13
- package/src/utils.ts +15 -80
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -247,16 +247,16 @@ var URLPath = class {
|
|
|
247
247
|
get object() {
|
|
248
248
|
return this.toObject();
|
|
249
249
|
}
|
|
250
|
-
/** Returns a map of path parameter names, or `
|
|
250
|
+
/** Returns a map of path parameter names, or `null` when the path has no parameters.
|
|
251
251
|
*
|
|
252
252
|
* @example
|
|
253
253
|
* ```ts
|
|
254
254
|
* new URLPath('/pet/{petId}').params // { petId: 'petId' }
|
|
255
|
-
* new URLPath('/pet').params //
|
|
255
|
+
* new URLPath('/pet').params // null
|
|
256
256
|
* ```
|
|
257
257
|
*/
|
|
258
258
|
get params() {
|
|
259
|
-
return this.
|
|
259
|
+
return this.toParamsObject();
|
|
260
260
|
}
|
|
261
261
|
#transformParam(raw) {
|
|
262
262
|
const param = isValidVarName(raw) ? raw : camelCase(raw);
|
|
@@ -274,7 +274,7 @@ var URLPath = class {
|
|
|
274
274
|
toObject({ type = "path", replacer, stringify } = {}) {
|
|
275
275
|
const object = {
|
|
276
276
|
url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }),
|
|
277
|
-
params: this.
|
|
277
|
+
params: this.toParamsObject()
|
|
278
278
|
};
|
|
279
279
|
if (stringify) {
|
|
280
280
|
if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, "");
|
|
@@ -290,12 +290,13 @@ var URLPath = class {
|
|
|
290
290
|
* @example
|
|
291
291
|
* new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'
|
|
292
292
|
*/
|
|
293
|
-
toTemplateString({ prefix
|
|
294
|
-
|
|
293
|
+
toTemplateString({ prefix, replacer } = {}) {
|
|
294
|
+
const result = this.path.split(/\{([^}]+)\}/).map((part, i) => {
|
|
295
295
|
if (i % 2 === 0) return part;
|
|
296
296
|
const param = this.#transformParam(part);
|
|
297
297
|
return `\${${replacer ? replacer(param) : param}}`;
|
|
298
|
-
}).join("")
|
|
298
|
+
}).join("");
|
|
299
|
+
return `\`${prefix ?? ""}${result}\``;
|
|
299
300
|
}
|
|
300
301
|
/**
|
|
301
302
|
* Extracts all `{param}` segments from the path and returns them as a key-value map.
|
|
@@ -304,17 +305,17 @@ var URLPath = class {
|
|
|
304
305
|
*
|
|
305
306
|
* @example
|
|
306
307
|
* ```ts
|
|
307
|
-
* new URLPath('/pet/{petId}/tag/{tagId}').
|
|
308
|
+
* new URLPath('/pet/{petId}/tag/{tagId}').toParamsObject()
|
|
308
309
|
* // { petId: 'petId', tagId: 'tagId' }
|
|
309
310
|
* ```
|
|
310
311
|
*/
|
|
311
|
-
|
|
312
|
+
toParamsObject(replacer) {
|
|
312
313
|
const params = {};
|
|
313
314
|
this.#eachParam((_raw, param) => {
|
|
314
315
|
const key = replacer ? replacer(param) : param;
|
|
315
316
|
params[key] = key;
|
|
316
317
|
});
|
|
317
|
-
return Object.keys(params).length > 0 ? params :
|
|
318
|
+
return Object.keys(params).length > 0 ? params : null;
|
|
318
319
|
}
|
|
319
320
|
/** Converts the OpenAPI path to Express-style colon syntax.
|
|
320
321
|
*
|
|
@@ -328,82 +329,144 @@ var URLPath = class {
|
|
|
328
329
|
}
|
|
329
330
|
};
|
|
330
331
|
//#endregion
|
|
331
|
-
//#region src/
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
const code = Number(res.statusCode);
|
|
338
|
-
if (code >= 200 && code < 300) return res.statusCode;
|
|
339
|
-
}
|
|
332
|
+
//#region ../../internals/shared/src/operation.ts
|
|
333
|
+
function getOperationLink(node, link) {
|
|
334
|
+
if (!link) return null;
|
|
335
|
+
if (typeof link === "function") return link(node) ?? null;
|
|
336
|
+
if (link === "urlPath") return node.path ? `{@link ${new URLPath(node.path).URL}}` : null;
|
|
337
|
+
return node.path ? `{@link ${node.path.replaceAll("{", ":").replaceAll("}", "")}}` : null;
|
|
340
338
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
* Build JSDoc comment lines from an OperationNode.
|
|
351
|
-
*/
|
|
352
|
-
function getComments(node) {
|
|
353
|
-
return [
|
|
339
|
+
function buildOperationComments(node, options = {}) {
|
|
340
|
+
const { link = "pathTemplate", linkPosition = "afterDeprecated", splitLines = false } = options;
|
|
341
|
+
const linkComment = getOperationLink(node, link);
|
|
342
|
+
const filteredComments = (linkPosition === "beforeDeprecated" ? [
|
|
343
|
+
node.description && `@description ${node.description}`,
|
|
344
|
+
node.summary && `@summary ${node.summary}`,
|
|
345
|
+
linkComment,
|
|
346
|
+
node.deprecated && "@deprecated"
|
|
347
|
+
] : [
|
|
354
348
|
node.description && `@description ${node.description}`,
|
|
355
349
|
node.summary && `@summary ${node.summary}`,
|
|
356
350
|
node.deprecated && "@deprecated",
|
|
357
|
-
|
|
358
|
-
].filter((
|
|
351
|
+
linkComment
|
|
352
|
+
]).filter((comment) => Boolean(comment));
|
|
353
|
+
if (!splitLines) return filteredComments;
|
|
354
|
+
return filteredComments.flatMap((text) => text.split(/\r?\n/).map((line) => line.trim())).filter((comment) => Boolean(comment));
|
|
359
355
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
356
|
+
function getOperationParameters(node, options = {}) {
|
|
357
|
+
const params = _kubb_core.ast.caseParams(node.parameters, options.paramsCasing);
|
|
358
|
+
return {
|
|
359
|
+
path: params.filter((param) => param.in === "path"),
|
|
360
|
+
query: params.filter((param) => param.in === "query"),
|
|
361
|
+
header: params.filter((param) => param.in === "header"),
|
|
362
|
+
cookie: params.filter((param) => param.in === "cookie")
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
function getStatusCodeNumber(statusCode) {
|
|
366
|
+
const code = Number(statusCode);
|
|
367
|
+
return Number.isNaN(code) ? null : code;
|
|
368
|
+
}
|
|
369
|
+
function isSuccessStatusCode(statusCode) {
|
|
370
|
+
const code = getStatusCodeNumber(statusCode);
|
|
371
|
+
return code !== null && code >= 200 && code < 300;
|
|
372
|
+
}
|
|
373
|
+
function isErrorStatusCode(statusCode) {
|
|
374
|
+
const code = getStatusCodeNumber(statusCode);
|
|
375
|
+
return code !== null && code >= 400;
|
|
376
|
+
}
|
|
377
|
+
function resolveErrorNames(node, resolver) {
|
|
378
|
+
return node.responses.filter((response) => isErrorStatusCode(response.statusCode)).map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
|
|
379
|
+
}
|
|
380
|
+
function resolveStatusCodeNames(node, resolver) {
|
|
381
|
+
return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode));
|
|
382
|
+
}
|
|
383
|
+
const typeNamesByResolver = /* @__PURE__ */ new WeakMap();
|
|
384
|
+
function resolveOperationTypeNames(node, resolver, options = {}) {
|
|
385
|
+
const cacheKey = `${node.operationId}\0${options.paramsCasing ?? ""}\0${options.order ?? ""}\0${options.responseStatusNames ?? ""}\0${(options.exclude ?? []).join(",")}`;
|
|
386
|
+
let byResolver = typeNamesByResolver.get(resolver);
|
|
387
|
+
if (byResolver) {
|
|
388
|
+
const cached = byResolver.get(cacheKey);
|
|
389
|
+
if (cached) return cached;
|
|
390
|
+
} else {
|
|
391
|
+
byResolver = /* @__PURE__ */ new Map();
|
|
392
|
+
typeNamesByResolver.set(resolver, byResolver);
|
|
372
393
|
}
|
|
373
|
-
|
|
394
|
+
const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing });
|
|
395
|
+
const responseStatusNames = options.responseStatusNames === "error" ? resolveErrorNames(node, resolver) : options.responseStatusNames === false ? [] : resolveStatusCodeNames(node, resolver);
|
|
396
|
+
const exclude = new Set(options.exclude ?? []);
|
|
397
|
+
const paramNames = [
|
|
398
|
+
...path.map((param) => resolver.resolvePathParamsName(node, param)),
|
|
399
|
+
...query.map((param) => resolver.resolveQueryParamsName(node, param)),
|
|
400
|
+
...header.map((param) => resolver.resolveHeaderParamsName(node, param))
|
|
401
|
+
];
|
|
402
|
+
const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null, resolver.resolveResponseName(node)];
|
|
403
|
+
const result = (options.order === "body-response-first" ? [
|
|
404
|
+
...bodyAndResponseNames,
|
|
405
|
+
...paramNames,
|
|
406
|
+
...responseStatusNames
|
|
407
|
+
] : [
|
|
408
|
+
...paramNames,
|
|
409
|
+
...bodyAndResponseNames,
|
|
410
|
+
...responseStatusNames
|
|
411
|
+
]).filter((name) => Boolean(name) && !exclude.has(name));
|
|
412
|
+
byResolver.set(cacheKey, result);
|
|
413
|
+
return result;
|
|
414
|
+
}
|
|
415
|
+
function findSuccessStatusCode(responses) {
|
|
416
|
+
for (const response of responses) if (isSuccessStatusCode(response.statusCode)) return response.statusCode;
|
|
417
|
+
return null;
|
|
374
418
|
}
|
|
419
|
+
//#endregion
|
|
420
|
+
//#region ../../internals/shared/src/group.ts
|
|
375
421
|
/**
|
|
376
|
-
*
|
|
377
|
-
*
|
|
422
|
+
* Builds the `group` config a Kubb plugin passes to `ctx.setOptions`, applying the
|
|
423
|
+
* shared default naming so every plugin groups output consistently:
|
|
424
|
+
*
|
|
425
|
+
* - `path` groups use the second path segment (`/pet/findByStatus` → `pet`).
|
|
426
|
+
* - other groups use `${camelCase(group)}${suffix}` (e.g. `petController`).
|
|
427
|
+
*
|
|
428
|
+
* A user-provided `group.name` always wins over the default namer, so callers stay in
|
|
429
|
+
* control of their output folders. Returns `null` when grouping is disabled, matching the
|
|
430
|
+
* per-plugin convention.
|
|
431
|
+
*
|
|
432
|
+
* @param group - The user-supplied group option, or `undefined` to disable grouping.
|
|
433
|
+
* @param options.suffix - Appended to non-`path` group names, e.g. `'Controller'` or `'Requests'`.
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* ```ts
|
|
437
|
+
* createGroupConfig(group, { suffix: 'Controller' }) // plugin-ts, plugin-client, …
|
|
438
|
+
* createGroupConfig(group, { suffix: 'Requests' }) // plugin-cypress, plugin-mcp
|
|
439
|
+
* ```
|
|
378
440
|
*/
|
|
379
|
-
function
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
441
|
+
function createGroupConfig(group, options) {
|
|
442
|
+
if (!group) return null;
|
|
443
|
+
const defaultName = (ctx) => {
|
|
444
|
+
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
445
|
+
return `${camelCase(ctx.group)}${options.suffix}`;
|
|
446
|
+
};
|
|
447
|
+
return {
|
|
448
|
+
...group,
|
|
449
|
+
name: group.name ? group.name : defaultName
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
//#endregion
|
|
453
|
+
//#region ../../internals/shared/src/params.ts
|
|
454
|
+
function buildParamsMapping(originalParams, mappedParams) {
|
|
455
|
+
const mapping = {};
|
|
456
|
+
let hasChanged = false;
|
|
457
|
+
originalParams.forEach((param, i) => {
|
|
458
|
+
const mappedName = mappedParams[i]?.name ?? param.name;
|
|
459
|
+
mapping[param.name] = mappedName;
|
|
460
|
+
if (param.name !== mappedName) hasChanged = true;
|
|
461
|
+
});
|
|
462
|
+
return hasChanged ? mapping : null;
|
|
463
|
+
}
|
|
464
|
+
function buildTransformedParamsMapping(params, transformName) {
|
|
465
|
+
if (!params.length) return null;
|
|
466
|
+
return buildParamsMapping(params, params.map((param) => ({
|
|
467
|
+
...param,
|
|
468
|
+
name: transformName(param.name)
|
|
469
|
+
})));
|
|
407
470
|
}
|
|
408
471
|
//#endregion
|
|
409
472
|
//#region src/components/McpHandler.tsx
|
|
@@ -415,16 +478,13 @@ function buildRemappingCode(mapping, varName, sourceName) {
|
|
|
415
478
|
}
|
|
416
479
|
const declarationPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "declaration" });
|
|
417
480
|
function McpHandler({ name, node, resolver, baseURL, dataReturnType, paramsCasing }) {
|
|
481
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
418
482
|
const urlPath = new URLPath(node.path);
|
|
419
483
|
const contentType = node.requestBody?.content?.[0]?.contentType;
|
|
420
484
|
const isFormData = contentType === "multipart/form-data";
|
|
421
|
-
const
|
|
422
|
-
const
|
|
423
|
-
const
|
|
424
|
-
const originalPathParams = node.parameters.filter((p) => p.in === "path");
|
|
425
|
-
const originalQueryParams = node.parameters.filter((p) => p.in === "query");
|
|
426
|
-
const originalHeaderParams = node.parameters.filter((p) => p.in === "header");
|
|
427
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : void 0;
|
|
485
|
+
const { query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing });
|
|
486
|
+
const { path: originalPathParams, query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node);
|
|
487
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : null;
|
|
428
488
|
const responseName = resolver.resolveResponseName(node);
|
|
429
489
|
const errorResponses = node.responses.filter((r) => Number(r.statusCode) >= 400).map((r) => resolver.resolveResponseStatusName(node, r.statusCode));
|
|
430
490
|
const generics = [
|
|
@@ -440,11 +500,11 @@ function McpHandler({ name, node, resolver, baseURL, dataReturnType, paramsCasin
|
|
|
440
500
|
});
|
|
441
501
|
const baseParamsSignature = declarationPrinter.print(paramsNode) ?? "";
|
|
442
502
|
const paramsSignature = baseParamsSignature ? `${baseParamsSignature}, request: RequestHandlerExtra<ServerRequest, ServerNotification>` : "request: RequestHandlerExtra<ServerRequest, ServerNotification>";
|
|
443
|
-
const pathParamsMapping = paramsCasing ?
|
|
444
|
-
const queryParamsMapping = paramsCasing ?
|
|
445
|
-
const headerParamsMapping = paramsCasing ?
|
|
446
|
-
const contentTypeHeader = contentType && contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` :
|
|
447
|
-
const headers = [headerParams.length ? headerParamsMapping ? "...mappedHeaders" : "...headers" :
|
|
503
|
+
const pathParamsMapping = paramsCasing ? buildTransformedParamsMapping(originalPathParams, camelCase) : null;
|
|
504
|
+
const queryParamsMapping = paramsCasing ? buildTransformedParamsMapping(originalQueryParams, camelCase) : null;
|
|
505
|
+
const headerParamsMapping = paramsCasing ? buildTransformedParamsMapping(originalHeaderParams, camelCase) : null;
|
|
506
|
+
const contentTypeHeader = contentType && contentType !== "application/json" && contentType !== "multipart/form-data" ? `'Content-Type': '${contentType}'` : null;
|
|
507
|
+
const headers = [headerParams.length ? headerParamsMapping ? "...mappedHeaders" : "...headers" : null, contentTypeHeader].filter(Boolean);
|
|
448
508
|
const fetchConfig = [];
|
|
449
509
|
fetchConfig.push(`method: ${JSON.stringify(node.method.toUpperCase())}`);
|
|
450
510
|
fetchConfig.push(`url: ${urlPath.template}`);
|
|
@@ -478,7 +538,7 @@ function McpHandler({ name, node, resolver, baseURL, dataReturnType, paramsCasin
|
|
|
478
538
|
async: true,
|
|
479
539
|
export: true,
|
|
480
540
|
params: paramsSignature,
|
|
481
|
-
JSDoc: { comments:
|
|
541
|
+
JSDoc: { comments: buildOperationComments(node) },
|
|
482
542
|
returnType: "Promise<CallToolResult>",
|
|
483
543
|
children: [
|
|
484
544
|
"",
|
|
@@ -500,7 +560,7 @@ function McpHandler({ name, node, resolver, baseURL, dataReturnType, paramsCasin
|
|
|
500
560
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
501
561
|
isFormData && requestName && "const formData = buildFormData(requestData)",
|
|
502
562
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
503
|
-
`const res = await
|
|
563
|
+
`const res = await client<${generics.join(", ")}>({ ${fetchConfig.join(", ")} }, request)`,
|
|
504
564
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)("br", {}),
|
|
505
565
|
callToolResult
|
|
506
566
|
]
|
|
@@ -508,62 +568,80 @@ function McpHandler({ name, node, resolver, baseURL, dataReturnType, paramsCasin
|
|
|
508
568
|
});
|
|
509
569
|
}
|
|
510
570
|
//#endregion
|
|
571
|
+
//#region src/utils.ts
|
|
572
|
+
/**
|
|
573
|
+
* Render a group param value — compose individual schemas into `z.object({ ... })`,
|
|
574
|
+
* or use a schema name string directly.
|
|
575
|
+
*/
|
|
576
|
+
function zodGroupExpr(entry) {
|
|
577
|
+
if (typeof entry === "string") return entry;
|
|
578
|
+
return `z.object({ ${entry.map((p) => `${JSON.stringify(p.name)}: ${p.schemaName}`).join(", ")} })`;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Convert a SchemaNode type to an inline Zod expression string.
|
|
582
|
+
* Used as fallback when no named zod schema is available for a path parameter.
|
|
583
|
+
*/
|
|
584
|
+
function zodExprFromSchemaNode(schema) {
|
|
585
|
+
const baseExpr = (() => {
|
|
586
|
+
if (schema.type === "enum") {
|
|
587
|
+
const rawValues = schema.namedEnumValues?.length ? schema.namedEnumValues.map((v) => v.value) : (schema.enumValues ?? []).filter((v) => v !== null);
|
|
588
|
+
if (rawValues.length > 0 && rawValues.every((v) => typeof v === "string")) return `z.enum([${rawValues.map((v) => JSON.stringify(v)).join(", ")}])`;
|
|
589
|
+
if (rawValues.length > 0) {
|
|
590
|
+
const literals = rawValues.map((v) => `z.literal(${JSON.stringify(v)})`);
|
|
591
|
+
return literals.length === 1 ? literals[0] : `z.union([${literals.join(", ")}])`;
|
|
592
|
+
}
|
|
593
|
+
return "z.string()";
|
|
594
|
+
}
|
|
595
|
+
if (schema.type === "integer") return "z.coerce.number()";
|
|
596
|
+
if (schema.type === "number") return "z.number()";
|
|
597
|
+
if (schema.type === "boolean") return "z.boolean()";
|
|
598
|
+
if (schema.type === "array") return "z.array(z.unknown())";
|
|
599
|
+
return "z.string()";
|
|
600
|
+
})();
|
|
601
|
+
return schema.nullable ? `${baseExpr}.nullable()` : baseExpr;
|
|
602
|
+
}
|
|
603
|
+
//#endregion
|
|
511
604
|
//#region src/components/Server.tsx
|
|
512
605
|
const keysPrinter = (0, _kubb_plugin_ts.functionPrinter)({ mode: "keys" });
|
|
513
606
|
function Server({ name, serverName, serverVersion, paramsCasing, operations }) {
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
otherEntries.sort((a, b) => a.key.localeCompare(b.key));
|
|
553
|
-
const entries = [...pathEntries, ...otherEntries];
|
|
554
|
-
const paramsNode = entries.length ? _kubb_core.ast.createFunctionParameters({ params: [_kubb_core.ast.createParameterGroup({ properties: entries.map((e) => _kubb_core.ast.createFunctionParameter({
|
|
555
|
-
name: e.key,
|
|
556
|
-
optional: false
|
|
557
|
-
})) })] }) : void 0;
|
|
558
|
-
const destructured = paramsNode ? keysPrinter.print(paramsNode) ?? "" : "";
|
|
559
|
-
const inputSchema = entries.length ? `{ ${entries.map((e) => `${e.key}: ${e.value}`).join(", ")} }` : void 0;
|
|
560
|
-
const outputSchema = zod.responseName;
|
|
561
|
-
const config = [
|
|
562
|
-
tool.title ? `title: ${JSON.stringify(tool.title)}` : null,
|
|
563
|
-
`description: ${JSON.stringify(tool.description)}`,
|
|
564
|
-
outputSchema ? `outputSchema: { data: ${outputSchema} }` : null
|
|
565
|
-
].filter(Boolean).join(",\n ");
|
|
566
|
-
if (inputSchema) return `
|
|
607
|
+
const registrations = operations.map(({ tool, mcp, zod, node }) => {
|
|
608
|
+
const { path: pathParams } = getOperationParameters(node, { paramsCasing });
|
|
609
|
+
const pathEntries = [];
|
|
610
|
+
const otherEntries = [];
|
|
611
|
+
for (const p of pathParams) {
|
|
612
|
+
const zodParam = zod.pathParams.find((zp) => zp.name === p.name);
|
|
613
|
+
pathEntries.push({
|
|
614
|
+
key: p.name,
|
|
615
|
+
value: zodParam ? zodParam.schemaName : zodExprFromSchemaNode(p.schema)
|
|
616
|
+
});
|
|
617
|
+
}
|
|
618
|
+
if (zod.requestName) otherEntries.push({
|
|
619
|
+
key: "data",
|
|
620
|
+
value: zod.requestName
|
|
621
|
+
});
|
|
622
|
+
if (zod.queryParams) otherEntries.push({
|
|
623
|
+
key: "params",
|
|
624
|
+
value: zodGroupExpr(zod.queryParams)
|
|
625
|
+
});
|
|
626
|
+
if (zod.headerParams) otherEntries.push({
|
|
627
|
+
key: "headers",
|
|
628
|
+
value: zodGroupExpr(zod.headerParams)
|
|
629
|
+
});
|
|
630
|
+
otherEntries.sort((a, b) => a.key.localeCompare(b.key));
|
|
631
|
+
const entries = [...pathEntries, ...otherEntries];
|
|
632
|
+
const paramsNode = entries.length ? _kubb_core.ast.createFunctionParameters({ params: [_kubb_core.ast.createParameterGroup({ properties: entries.map((e) => _kubb_core.ast.createFunctionParameter({
|
|
633
|
+
name: e.key,
|
|
634
|
+
optional: false
|
|
635
|
+
})) })] }) : null;
|
|
636
|
+
const destructured = paramsNode ? keysPrinter.print(paramsNode) ?? "" : "";
|
|
637
|
+
const inputSchema = entries.length ? `{ ${entries.map((e) => `${e.key}: ${e.value}`).join(", ")} }` : null;
|
|
638
|
+
const outputSchema = zod.responseName;
|
|
639
|
+
const config = [
|
|
640
|
+
tool.title ? `title: ${JSON.stringify(tool.title)}` : null,
|
|
641
|
+
`description: ${JSON.stringify(tool.description)}`,
|
|
642
|
+
outputSchema ? `outputSchema: { data: ${outputSchema} }` : null
|
|
643
|
+
].filter(Boolean).join(",\n ");
|
|
644
|
+
if (inputSchema) return `
|
|
567
645
|
server.registerTool(${JSON.stringify(tool.name)}, {
|
|
568
646
|
${config},
|
|
569
647
|
inputSchema: ${inputSchema},
|
|
@@ -571,14 +649,34 @@ server.registerTool(${JSON.stringify(tool.name)}, {
|
|
|
571
649
|
return ${mcp.name}(${destructured}, request)
|
|
572
650
|
})
|
|
573
651
|
`;
|
|
574
|
-
|
|
652
|
+
return `
|
|
575
653
|
server.registerTool(${JSON.stringify(tool.name)}, {
|
|
576
654
|
${config},
|
|
577
655
|
}, async (request) => {
|
|
578
656
|
return ${mcp.name}(request)
|
|
579
657
|
})
|
|
580
658
|
`;
|
|
581
|
-
|
|
659
|
+
}).filter(Boolean).join("\n");
|
|
660
|
+
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File.Source, {
|
|
661
|
+
name,
|
|
662
|
+
isExportable: true,
|
|
663
|
+
isIndexable: true,
|
|
664
|
+
children: [
|
|
665
|
+
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Function, {
|
|
666
|
+
name: "getServer",
|
|
667
|
+
export: true,
|
|
668
|
+
children: `const server = new McpServer({
|
|
669
|
+
name: '${serverName}',
|
|
670
|
+
version: '${serverVersion}',
|
|
671
|
+
})
|
|
672
|
+
${registrations}
|
|
673
|
+
return server`
|
|
674
|
+
}),
|
|
675
|
+
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Const, {
|
|
676
|
+
name: "server",
|
|
677
|
+
export: true,
|
|
678
|
+
children: "getServer()"
|
|
679
|
+
}),
|
|
582
680
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.Function, {
|
|
583
681
|
name: "startServer",
|
|
584
682
|
async: true,
|
|
@@ -597,29 +695,28 @@ server.registerTool(${JSON.stringify(tool.name)}, {
|
|
|
597
695
|
}
|
|
598
696
|
//#endregion
|
|
599
697
|
//#region src/generators/mcpGenerator.tsx
|
|
698
|
+
/**
|
|
699
|
+
* Built-in operation generator for `@kubb/plugin-mcp`. Emits one MCP tool
|
|
700
|
+
* handler per OpenAPI operation, wiring the input Zod schema, the HTTP call,
|
|
701
|
+
* and the response shape into a single function that an MCP server can
|
|
702
|
+
* register as a callable tool.
|
|
703
|
+
*/
|
|
600
704
|
const mcpGenerator = (0, _kubb_core.defineGenerator)({
|
|
601
705
|
name: "mcp",
|
|
602
|
-
renderer: _kubb_renderer_jsx.
|
|
706
|
+
renderer: _kubb_renderer_jsx.jsxRendererSync,
|
|
603
707
|
operation(node, ctx) {
|
|
708
|
+
if (!_kubb_core.ast.isHttpOperationNode(node)) return null;
|
|
604
709
|
const { resolver, driver, root } = ctx;
|
|
605
710
|
const { output, client, paramsCasing, group } = ctx.options;
|
|
606
711
|
const pluginTs = driver.getPlugin(_kubb_plugin_ts.pluginTsName);
|
|
607
712
|
if (!pluginTs) return null;
|
|
608
713
|
const tsResolver = driver.getResolver(_kubb_plugin_ts.pluginTsName);
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
const importedTypeNames = [
|
|
614
|
-
...pathParams.map((p) => tsResolver.resolvePathParamsName(node, p)),
|
|
615
|
-
...queryParams.map((p) => tsResolver.resolveQueryParamsName(node, p)),
|
|
616
|
-
...headerParams.map((p) => tsResolver.resolveHeaderParamsName(node, p)),
|
|
617
|
-
node.requestBody?.content?.[0]?.schema ? tsResolver.resolveDataName(node) : void 0,
|
|
618
|
-
tsResolver.resolveResponseName(node),
|
|
619
|
-
...node.responses.filter((r) => Number(r.statusCode) >= 400).map((r) => tsResolver.resolveResponseStatusName(node, r.statusCode))
|
|
620
|
-
].filter(Boolean);
|
|
714
|
+
const importedTypeNames = resolveOperationTypeNames(node, tsResolver, {
|
|
715
|
+
paramsCasing,
|
|
716
|
+
responseStatusNames: "error"
|
|
717
|
+
});
|
|
621
718
|
const meta = {
|
|
622
|
-
name: resolver.
|
|
719
|
+
name: resolver.resolveHandlerName(node),
|
|
623
720
|
file: resolver.resolveFile({
|
|
624
721
|
name: node.operationId,
|
|
625
722
|
extname: ".ts",
|
|
@@ -628,7 +725,7 @@ const mcpGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
628
725
|
}, {
|
|
629
726
|
root,
|
|
630
727
|
output,
|
|
631
|
-
group
|
|
728
|
+
group: group ?? void 0
|
|
632
729
|
}),
|
|
633
730
|
fileTs: tsResolver.resolveFile({
|
|
634
731
|
name: node.operationId,
|
|
@@ -638,7 +735,7 @@ const mcpGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
638
735
|
}, {
|
|
639
736
|
root,
|
|
640
737
|
output: pluginTs.options?.output ?? output,
|
|
641
|
-
group: pluginTs.options?.group
|
|
738
|
+
group: pluginTs.options?.group ?? void 0
|
|
642
739
|
})
|
|
643
740
|
};
|
|
644
741
|
return /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsxs)(_kubb_renderer_jsx.File, {
|
|
@@ -682,7 +779,7 @@ const mcpGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
682
779
|
isTypeOnly: true
|
|
683
780
|
}),
|
|
684
781
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
685
|
-
name: "
|
|
782
|
+
name: "client",
|
|
686
783
|
path: client.importPath
|
|
687
784
|
}),
|
|
688
785
|
client.dataReturnType === "full" && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -698,18 +795,18 @@ const mcpGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
698
795
|
"ResponseErrorConfig"
|
|
699
796
|
],
|
|
700
797
|
root: meta.file.path,
|
|
701
|
-
path: node_path.default.resolve(root, ".kubb/
|
|
798
|
+
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
702
799
|
isTypeOnly: true
|
|
703
800
|
}),
|
|
704
801
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
705
|
-
name: ["
|
|
802
|
+
name: ["client"],
|
|
706
803
|
root: meta.file.path,
|
|
707
|
-
path: node_path.default.resolve(root, ".kubb/
|
|
804
|
+
path: node_path.default.resolve(root, ".kubb/client.ts")
|
|
708
805
|
}),
|
|
709
806
|
client.dataReturnType === "full" && /* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
710
807
|
name: ["ResponseConfig"],
|
|
711
808
|
root: meta.file.path,
|
|
712
|
-
path: node_path.default.resolve(root, ".kubb/
|
|
809
|
+
path: node_path.default.resolve(root, ".kubb/client.ts"),
|
|
713
810
|
isTypeOnly: true
|
|
714
811
|
})
|
|
715
812
|
] }),
|
|
@@ -736,9 +833,9 @@ const mcpGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
736
833
|
*/
|
|
737
834
|
const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
738
835
|
name: "operations",
|
|
739
|
-
renderer: _kubb_renderer_jsx.
|
|
836
|
+
renderer: _kubb_renderer_jsx.jsxRendererSync,
|
|
740
837
|
operations(nodes, ctx) {
|
|
741
|
-
const {
|
|
838
|
+
const { config, resolver, plugin, driver, root } = ctx;
|
|
742
839
|
const { output, paramsCasing, group } = ctx.options;
|
|
743
840
|
const pluginZod = driver.getPlugin(_kubb_plugin_zod.pluginZodName);
|
|
744
841
|
if (!pluginZod) return;
|
|
@@ -754,11 +851,8 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
754
851
|
path: node_path.default.resolve(root, output.path, ".mcp.json"),
|
|
755
852
|
meta: { pluginName: plugin.name }
|
|
756
853
|
};
|
|
757
|
-
const operationsMapped = nodes.map((node) => {
|
|
758
|
-
const
|
|
759
|
-
const pathParams = casedParams.filter((p) => p.in === "path");
|
|
760
|
-
const queryParams = casedParams.filter((p) => p.in === "query");
|
|
761
|
-
const headerParams = casedParams.filter((p) => p.in === "header");
|
|
854
|
+
const operationsMapped = nodes.filter(_kubb_core.ast.isHttpOperationNode).map((node) => {
|
|
855
|
+
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing });
|
|
762
856
|
const mcpFile = resolver.resolveFile({
|
|
763
857
|
name: node.operationId,
|
|
764
858
|
extname: ".ts",
|
|
@@ -767,7 +861,7 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
767
861
|
}, {
|
|
768
862
|
root,
|
|
769
863
|
output,
|
|
770
|
-
group
|
|
864
|
+
group: group ?? void 0
|
|
771
865
|
});
|
|
772
866
|
const zodFile = zodResolver.resolveFile({
|
|
773
867
|
name: node.operationId,
|
|
@@ -777,11 +871,11 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
777
871
|
}, {
|
|
778
872
|
root,
|
|
779
873
|
output: pluginZod.options?.output ?? output,
|
|
780
|
-
group: pluginZod.options?.group
|
|
874
|
+
group: pluginZod.options?.group ?? void 0
|
|
781
875
|
});
|
|
782
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName(node) :
|
|
876
|
+
const requestName = node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName(node) : null;
|
|
783
877
|
const successStatus = findSuccessStatusCode(node.responses);
|
|
784
|
-
const responseName = successStatus ? zodResolver.resolveResponseStatusName(node, successStatus) :
|
|
878
|
+
const responseName = successStatus ? zodResolver.resolveResponseStatusName(node, successStatus) : null;
|
|
785
879
|
const resolveParams = (params) => params.map((p) => ({
|
|
786
880
|
name: p.name,
|
|
787
881
|
schemaName: zodResolver.resolveParamName(node, p)
|
|
@@ -793,13 +887,13 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
793
887
|
description: node.description || `Make a ${node.method.toUpperCase()} request to ${node.path}`
|
|
794
888
|
},
|
|
795
889
|
mcp: {
|
|
796
|
-
name: resolver.
|
|
890
|
+
name: resolver.resolveHandlerName(node),
|
|
797
891
|
file: mcpFile
|
|
798
892
|
},
|
|
799
893
|
zod: {
|
|
800
894
|
pathParams: resolveParams(pathParams),
|
|
801
|
-
queryParams: queryParams.length ? resolveParams(queryParams) :
|
|
802
|
-
headerParams: headerParams.length ? resolveParams(headerParams) :
|
|
895
|
+
queryParams: queryParams.length ? resolveParams(queryParams) : null,
|
|
896
|
+
headerParams: headerParams.length ? resolveParams(headerParams) : null,
|
|
803
897
|
requestName,
|
|
804
898
|
responseName,
|
|
805
899
|
file: zodFile
|
|
@@ -814,7 +908,7 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
814
908
|
...(zod.headerParams ?? []).map((p) => p.schemaName),
|
|
815
909
|
zod.requestName,
|
|
816
910
|
zod.responseName
|
|
817
|
-
].filter(Boolean);
|
|
911
|
+
].filter((name) => Boolean(name));
|
|
818
912
|
const uniqueNames = [...new Set(zodNames)].sort();
|
|
819
913
|
return [/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
820
914
|
name: [mcp.name],
|
|
@@ -830,13 +924,21 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
830
924
|
baseName: serverFile.baseName,
|
|
831
925
|
path: serverFile.path,
|
|
832
926
|
meta: serverFile.meta,
|
|
833
|
-
banner: resolver.resolveBanner(
|
|
927
|
+
banner: resolver.resolveBanner(ctx.meta, {
|
|
834
928
|
output,
|
|
835
|
-
config
|
|
929
|
+
config,
|
|
930
|
+
file: {
|
|
931
|
+
path: serverFile.path,
|
|
932
|
+
baseName: serverFile.baseName
|
|
933
|
+
}
|
|
836
934
|
}),
|
|
837
|
-
footer: resolver.resolveFooter(
|
|
935
|
+
footer: resolver.resolveFooter(ctx.meta, {
|
|
838
936
|
output,
|
|
839
|
-
config
|
|
937
|
+
config,
|
|
938
|
+
file: {
|
|
939
|
+
path: serverFile.path,
|
|
940
|
+
baseName: serverFile.baseName
|
|
941
|
+
}
|
|
840
942
|
}),
|
|
841
943
|
children: [
|
|
842
944
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(_kubb_renderer_jsx.File.Import, {
|
|
@@ -854,8 +956,8 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
854
956
|
imports,
|
|
855
957
|
/* @__PURE__ */ (0, _kubb_renderer_jsx_jsx_runtime.jsx)(Server, {
|
|
856
958
|
name,
|
|
857
|
-
serverName:
|
|
858
|
-
serverVersion:
|
|
959
|
+
serverName: ctx.meta.title ?? "server",
|
|
960
|
+
serverVersion: ctx.meta.version ?? "0.0.0",
|
|
859
961
|
paramsCasing,
|
|
860
962
|
operations: operationsMapped
|
|
861
963
|
})
|
|
@@ -869,7 +971,7 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
869
971
|
children: `
|
|
870
972
|
{
|
|
871
973
|
"mcpServers": {
|
|
872
|
-
"${
|
|
974
|
+
"${ctx.meta.title || "server"}": {
|
|
873
975
|
"type": "stdio",
|
|
874
976
|
"command": "npx",
|
|
875
977
|
"args": ["tsx", "${node_path.default.relative(node_path.default.dirname(jsonFile.path), serverFile.path)}"]
|
|
@@ -884,14 +986,18 @@ const serverGenerator = (0, _kubb_core.defineGenerator)({
|
|
|
884
986
|
//#endregion
|
|
885
987
|
//#region src/resolvers/resolverMcp.ts
|
|
886
988
|
/**
|
|
887
|
-
*
|
|
989
|
+
* Default resolver used by `@kubb/plugin-mcp`. Decides the names and file
|
|
990
|
+
* paths for every generated MCP tool handler. Function names get a `Handler`
|
|
991
|
+
* suffix so an operation `addPet` becomes `addPetHandler`.
|
|
888
992
|
*
|
|
889
|
-
*
|
|
993
|
+
* @example Resolve a handler name
|
|
994
|
+
* ```ts
|
|
995
|
+
* import { resolverMcp } from '@kubb/plugin-mcp'
|
|
890
996
|
*
|
|
891
|
-
*
|
|
892
|
-
*
|
|
997
|
+
* resolverMcp.default('addPet', 'function') // 'addPetHandler'
|
|
998
|
+
* ```
|
|
893
999
|
*/
|
|
894
|
-
const resolverMcp = (0, _kubb_core.defineResolver)((
|
|
1000
|
+
const resolverMcp = (0, _kubb_core.defineResolver)(() => ({
|
|
895
1001
|
name: "default",
|
|
896
1002
|
pluginName: "plugin-mcp",
|
|
897
1003
|
default(name, type) {
|
|
@@ -899,12 +1005,50 @@ const resolverMcp = (0, _kubb_core.defineResolver)((ctx) => ({
|
|
|
899
1005
|
return camelCase(name, { suffix: "handler" });
|
|
900
1006
|
},
|
|
901
1007
|
resolveName(name) {
|
|
902
|
-
return
|
|
1008
|
+
return this.default(name, "function");
|
|
1009
|
+
},
|
|
1010
|
+
resolvePathName(name, type) {
|
|
1011
|
+
return this.default(name, type);
|
|
1012
|
+
},
|
|
1013
|
+
resolveHandlerName(node) {
|
|
1014
|
+
return this.resolveName(node.operationId);
|
|
903
1015
|
}
|
|
904
1016
|
}));
|
|
905
1017
|
//#endregion
|
|
906
1018
|
//#region src/plugin.ts
|
|
1019
|
+
/**
|
|
1020
|
+
* Canonical plugin name for `@kubb/plugin-mcp`. Used for driver lookups and
|
|
1021
|
+
* cross-plugin dependency references.
|
|
1022
|
+
*/
|
|
907
1023
|
const pluginMcpName = "plugin-mcp";
|
|
1024
|
+
/**
|
|
1025
|
+
* Generates a Model Context Protocol (MCP) server from an OpenAPI spec. Every
|
|
1026
|
+
* operation becomes a typed MCP tool that AI assistants (Claude Desktop, Claude
|
|
1027
|
+
* Code, MCP-compatible clients) can call directly.
|
|
1028
|
+
*
|
|
1029
|
+
* @example
|
|
1030
|
+
* ```ts
|
|
1031
|
+
* import { defineConfig } from 'kubb'
|
|
1032
|
+
* import { pluginTs } from '@kubb/plugin-ts'
|
|
1033
|
+
* import { pluginClient } from '@kubb/plugin-client'
|
|
1034
|
+
* import { pluginZod } from '@kubb/plugin-zod'
|
|
1035
|
+
* import { pluginMcp } from '@kubb/plugin-mcp'
|
|
1036
|
+
*
|
|
1037
|
+
* export default defineConfig({
|
|
1038
|
+
* input: { path: './petStore.yaml' },
|
|
1039
|
+
* output: { path: './src/gen' },
|
|
1040
|
+
* plugins: [
|
|
1041
|
+
* pluginTs(),
|
|
1042
|
+
* pluginClient(),
|
|
1043
|
+
* pluginZod(),
|
|
1044
|
+
* pluginMcp({
|
|
1045
|
+
* output: { path: './mcp' },
|
|
1046
|
+
* client: { baseURL: 'https://petstore.swagger.io/v2' },
|
|
1047
|
+
* }),
|
|
1048
|
+
* ],
|
|
1049
|
+
* })
|
|
1050
|
+
* ```
|
|
1051
|
+
*/
|
|
908
1052
|
const pluginMcp = (0, _kubb_core.definePlugin)((options) => {
|
|
909
1053
|
const { output = {
|
|
910
1054
|
path: "mcp",
|
|
@@ -912,13 +1056,7 @@ const pluginMcp = (0, _kubb_core.definePlugin)((options) => {
|
|
|
912
1056
|
}, group, exclude = [], include, override = [], paramsCasing, client, resolver: userResolver, transformer: userTransformer, generators: userGenerators = [] } = options;
|
|
913
1057
|
const clientName = client?.client ?? "axios";
|
|
914
1058
|
const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : void 0);
|
|
915
|
-
const groupConfig = group
|
|
916
|
-
...group,
|
|
917
|
-
name: group.name ? group.name : (ctx) => {
|
|
918
|
-
if (group.type === "path") return `${ctx.group.split("/")[1]}`;
|
|
919
|
-
return `${camelCase(ctx.group)}Requests`;
|
|
920
|
-
}
|
|
921
|
-
} : void 0;
|
|
1059
|
+
const groupConfig = createGroupConfig(group, { suffix: "Requests" });
|
|
922
1060
|
return {
|
|
923
1061
|
name: pluginMcpName,
|
|
924
1062
|
options,
|
|
@@ -954,10 +1092,10 @@ const pluginMcp = (0, _kubb_core.definePlugin)((options) => {
|
|
|
954
1092
|
const root = node_path$1.default.resolve(ctx.config.root, ctx.config.output.path);
|
|
955
1093
|
const hasClientPlugin = ctx.config.plugins?.some((p) => p.name === _kubb_plugin_client.pluginClientName);
|
|
956
1094
|
if (client?.bundle && !hasClientPlugin && !clientImportPath) ctx.injectFile({
|
|
957
|
-
baseName: "
|
|
958
|
-
path: node_path$1.default.resolve(root, ".kubb/
|
|
1095
|
+
baseName: "client.ts",
|
|
1096
|
+
path: node_path$1.default.resolve(root, ".kubb/client.ts"),
|
|
959
1097
|
sources: [_kubb_core.ast.createSource({
|
|
960
|
-
name: "
|
|
1098
|
+
name: "client",
|
|
961
1099
|
nodes: [_kubb_core.ast.createText(clientName === "fetch" ? _kubb_plugin_client_templates_clients_fetch_source.source : _kubb_plugin_client_templates_clients_axios_source.source)],
|
|
962
1100
|
isExportable: true,
|
|
963
1101
|
isIndexable: true
|