@kubb/plugin-mcp 5.0.0-alpha.9 → 5.0.0-beta.10

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.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["fetchClientSource","axiosClientSource","configSource"],"sources":["../src/plugin.ts"],"sourcesContent":["import path from 'node:path'\nimport { camelCase } from '@internals/utils'\nimport { createPlugin, type Group, getBarrelFiles, getMode } from '@kubb/core'\nimport { pluginClientName } from '@kubb/plugin-client'\nimport { source as axiosClientSource } from '@kubb/plugin-client/templates/clients/axios.source'\nimport { source as fetchClientSource } from '@kubb/plugin-client/templates/clients/fetch.source'\nimport { source as configSource } from '@kubb/plugin-client/templates/config.source'\nimport { OperationGenerator, pluginOasName } from '@kubb/plugin-oas'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { pluginZodName } from '@kubb/plugin-zod'\nimport { mcpGenerator, serverGenerator } from './generators'\nimport type { PluginMcp } from './types.ts'\n\nexport const pluginMcpName = 'plugin-mcp' satisfies PluginMcp['name']\n\nexport const pluginMcp = createPlugin<PluginMcp>((options) => {\n const {\n output = { path: 'mcp', barrelType: 'named' },\n group,\n exclude = [],\n include,\n override = [],\n transformers = {},\n generators = [mcpGenerator, serverGenerator].filter(Boolean),\n contentType,\n paramsCasing,\n client,\n } = options\n\n const clientName = client?.client ?? 'axios'\n const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : undefined)\n\n return {\n name: pluginMcpName,\n options: {\n output,\n group,\n paramsCasing,\n client: {\n client: clientName,\n clientType: client?.clientType ?? 'function',\n importPath: clientImportPath,\n dataReturnType: client?.dataReturnType ?? 'data',\n bundle: client?.bundle,\n baseURL: client?.baseURL,\n paramsCasing: client?.paramsCasing,\n },\n },\n pre: [pluginOasName, pluginTsName, pluginZodName].filter(Boolean),\n resolvePath(baseName, pathMode, options) {\n const root = path.resolve(this.config.root, this.config.output.path)\n const mode = pathMode ?? getMode(path.resolve(root, output.path))\n\n if (mode === 'single') {\n /**\n * when output is a file then we will always append to the same file(output file), see fileManager.addOrAppend\n * Other plugins then need to call addOrAppend instead of just add from the fileManager class\n */\n return path.resolve(root, output.path)\n }\n\n if (group && (options?.group?.path || options?.group?.tag)) {\n const groupName: Group['name'] = group?.name\n ? group.name\n : (ctx) => {\n if (group?.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n return `${camelCase(ctx.group)}Requests`\n }\n\n return path.resolve(\n root,\n output.path,\n groupName({\n group: group.type === 'path' ? options.group.path! : options.group.tag!,\n }),\n baseName,\n )\n }\n\n return path.resolve(root, output.path, baseName)\n },\n resolveName(name, type) {\n const resolvedName = camelCase(name, {\n isFile: type === 'file',\n })\n\n if (type) {\n return transformers?.name?.(resolvedName, type) || resolvedName\n }\n\n return resolvedName\n },\n async install() {\n const root = path.resolve(this.config.root, this.config.output.path)\n const mode = getMode(path.resolve(root, output.path))\n const oas = await this.getOas()\n const baseURL = await this.getBaseURL()\n\n if (baseURL) {\n this.plugin.options.client.baseURL = baseURL\n }\n\n const hasClientPlugin = !!this.driver.getPluginByName(pluginClientName)\n\n if (this.plugin.options.client.bundle && !hasClientPlugin && !this.plugin.options.client.importPath) {\n // pre add bundled fetch\n await this.addFile({\n baseName: 'fetch.ts',\n path: path.resolve(root, '.kubb/fetch.ts'),\n sources: [\n {\n name: 'fetch',\n value: this.plugin.options.client.client === 'fetch' ? fetchClientSource : axiosClientSource,\n isExportable: true,\n isIndexable: true,\n },\n ],\n imports: [],\n exports: [],\n })\n }\n\n if (!hasClientPlugin) {\n await this.addFile({\n baseName: 'config.ts',\n path: path.resolve(root, '.kubb/config.ts'),\n sources: [\n {\n name: 'config',\n value: configSource,\n isExportable: false,\n isIndexable: false,\n },\n ],\n imports: [],\n exports: [],\n })\n }\n\n const operationGenerator = new OperationGenerator(this.plugin.options, {\n fabric: this.fabric,\n oas,\n driver: this.driver,\n events: this.events,\n plugin: this.plugin,\n contentType,\n exclude,\n include,\n override,\n mode,\n })\n\n const files = await operationGenerator.build(...generators)\n await this.upsertFile(...files)\n\n const barrelFiles = await getBarrelFiles(this.fabric.files, {\n type: output.barrelType ?? 'named',\n root,\n output,\n meta: {\n pluginName: this.plugin.name,\n },\n })\n\n await this.upsertFile(...barrelFiles)\n },\n }\n})\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["#options","#transformParam","#eachParam","fetchClientSource","axiosClientSource","configSource"],"sources":["../../../internals/utils/src/casing.ts","../../../internals/utils/src/reserved.ts","../../../internals/utils/src/urlPath.ts","../../../internals/shared/src/operation.ts","../../../internals/shared/src/params.ts","../src/components/McpHandler.tsx","../src/utils.ts","../src/components/Server.tsx","../src/generators/mcpGenerator.tsx","../src/generators/serverGenerator.tsx","../src/resolvers/resolverMcp.ts","../src/plugin.ts"],"sourcesContent":["type Options = {\n /**\n * When `true`, dot-separated segments are split on `.` and joined with `/` after casing.\n */\n isFile?: boolean\n /**\n * Text prepended before casing is applied.\n */\n prefix?: string\n /**\n * Text appended before casing is applied.\n */\n suffix?: string\n}\n\n/**\n * Shared implementation for camelCase and PascalCase conversion.\n * Splits on common word boundaries (spaces, hyphens, underscores, dots, slashes, colons)\n * and capitalizes each word according to `pascal`.\n *\n * When `pascal` is `true` the first word is also capitalized (PascalCase), otherwise only subsequent words are.\n */\nfunction toCamelOrPascal(text: string, pascal: boolean): string {\n const normalized = text\n .trim()\n .replace(/([a-z\\d])([A-Z])/g, '$1 $2')\n .replace(/([A-Z]+)([A-Z][a-z])/g, '$1 $2')\n .replace(/(\\d)([a-z])/g, '$1 $2')\n\n const words = normalized.split(/[\\s\\-_./\\\\:]+/).filter(Boolean)\n\n return words\n .map((word, i) => {\n const allUpper = word.length > 1 && word === word.toUpperCase()\n if (allUpper) return word\n if (i === 0 && !pascal) return word.charAt(0).toLowerCase() + word.slice(1)\n return word.charAt(0).toUpperCase() + word.slice(1)\n })\n .join('')\n .replace(/[^a-zA-Z0-9]/g, '')\n}\n\n/**\n * Splits `text` on `.` and applies `transformPart` to each segment.\n * The last segment receives `isLast = true`, all earlier segments receive `false`.\n * Segments are joined with `/` to form a file path.\n *\n * Only splits on dots followed by a letter so that version numbers\n * embedded in operationIds (e.g. `v2025.0`) are kept intact.\n */\nfunction applyToFileParts(text: string, transformPart: (part: string, isLast: boolean) => string): string {\n const parts = text.split(/\\.(?=[a-zA-Z])/)\n return parts.map((part, i) => transformPart(part, i === parts.length - 1)).join('/')\n}\n\n/**\n * Converts `text` to camelCase.\n * When `isFile` is `true`, dot-separated segments are each cased independently and joined with `/`.\n *\n * @example\n * camelCase('hello-world') // 'helloWorld'\n * camelCase('pet.petId', { isFile: true }) // 'pet/petId'\n */\nexport function camelCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => camelCase(part, isLast ? { prefix, suffix } : {}))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, false)\n}\n\n/**\n * Converts `text` to PascalCase.\n * When `isFile` is `true`, the last dot-separated segment is PascalCased and earlier segments are camelCased.\n *\n * @example\n * pascalCase('hello-world') // 'HelloWorld'\n * pascalCase('pet.petId', { isFile: true }) // 'pet/PetId'\n */\nexport function pascalCase(text: string, { isFile, prefix = '', suffix = '' }: Options = {}): string {\n if (isFile) {\n return applyToFileParts(text, (part, isLast) => (isLast ? pascalCase(part, { prefix, suffix }) : camelCase(part)))\n }\n\n return toCamelOrPascal(`${prefix} ${text} ${suffix}`, true)\n}\n\n/**\n * Converts `text` to snake_case.\n *\n * @example\n * snakeCase('helloWorld') // 'hello_world'\n * snakeCase('Hello-World') // 'hello_world'\n */\nexport function snakeCase(text: string, { prefix = '', suffix = '' }: Omit<Options, 'isFile'> = {}): string {\n const processed = `${prefix} ${text} ${suffix}`.trim()\n return processed\n .replace(/([a-z])([A-Z])/g, '$1_$2')\n .replace(/[\\s\\-.]+/g, '_')\n .replace(/[^a-zA-Z0-9_]/g, '')\n .toLowerCase()\n .split('_')\n .filter(Boolean)\n .join('_')\n}\n\n/**\n * Converts `text` to SCREAMING_SNAKE_CASE.\n *\n * @example\n * screamingSnakeCase('helloWorld') // 'HELLO_WORLD'\n */\nexport function screamingSnakeCase(text: string, { prefix = '', suffix = '' }: Omit<Options, 'isFile'> = {}): string {\n return snakeCase(text, { prefix, suffix }).toUpperCase()\n}\n","/**\n * JavaScript and Java reserved words.\n * @link https://github.com/jonschlinkert/reserved/blob/master/index.js\n */\nconst reservedWords = new Set([\n 'abstract',\n 'arguments',\n 'boolean',\n 'break',\n 'byte',\n 'case',\n 'catch',\n 'char',\n 'class',\n 'const',\n 'continue',\n 'debugger',\n 'default',\n 'delete',\n 'do',\n 'double',\n 'else',\n 'enum',\n 'eval',\n 'export',\n 'extends',\n 'false',\n 'final',\n 'finally',\n 'float',\n 'for',\n 'function',\n 'goto',\n 'if',\n 'implements',\n 'import',\n 'in',\n 'instanceof',\n 'int',\n 'interface',\n 'let',\n 'long',\n 'native',\n 'new',\n 'null',\n 'package',\n 'private',\n 'protected',\n 'public',\n 'return',\n 'short',\n 'static',\n 'super',\n 'switch',\n 'synchronized',\n 'this',\n 'throw',\n 'throws',\n 'transient',\n 'true',\n 'try',\n 'typeof',\n 'var',\n 'void',\n 'volatile',\n 'while',\n 'with',\n 'yield',\n 'Array',\n 'Date',\n 'hasOwnProperty',\n 'Infinity',\n 'isFinite',\n 'isNaN',\n 'isPrototypeOf',\n 'length',\n 'Math',\n 'name',\n 'NaN',\n 'Number',\n 'Object',\n 'prototype',\n 'String',\n 'toString',\n 'undefined',\n 'valueOf',\n] as const)\n\n/**\n * Returns `true` when `name` is a syntactically valid JavaScript variable name.\n *\n * @example\n * ```ts\n * isValidVarName('status') // true\n * isValidVarName('class') // false (reserved word)\n * isValidVarName('42foo') // false (starts with digit)\n * ```\n */\nexport function isValidVarName(name: string): boolean {\n if (!name || reservedWords.has(name as 'valueOf')) {\n return false\n }\n return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name)\n}\n","import { camelCase } from './casing.ts'\nimport { isValidVarName } from './reserved.ts'\n\nexport type URLObject = {\n /**\n * The resolved URL string (Express-style or template literal, depending on context).\n */\n url: string\n /**\n * Extracted path parameters as a key-value map, or `undefined` when the path has none.\n */\n params?: Record<string, string>\n}\n\ntype ObjectOptions = {\n /**\n * Controls whether the `url` is rendered as an Express path or a template literal.\n * @default 'path'\n */\n type?: 'path' | 'template'\n /**\n * Optional transform applied to each extracted parameter name.\n */\n replacer?: (pathParam: string) => string\n /**\n * When `true`, the result is serialized to a string expression instead of a plain object.\n */\n stringify?: boolean\n}\n\n/**\n * Supported identifier casing strategies for path parameters.\n */\ntype PathCasing = 'camelcase'\n\ntype Options = {\n /**\n * Casing strategy applied to path parameter names.\n * @default undefined (original identifier preserved)\n */\n casing?: PathCasing\n}\n\n/**\n * Parses and transforms an OpenAPI/Swagger path string into various URL formats.\n *\n * @example\n * const p = new URLPath('/pet/{petId}')\n * p.URL // '/pet/:petId'\n * p.template // '`/pet/${petId}`'\n */\nexport class URLPath {\n /**\n * The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`.\n */\n path: string\n\n #options: Options\n\n constructor(path: string, options: Options = {}) {\n this.path = path\n this.#options = options\n }\n\n /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}').URL // '/pet/:petId'\n * ```\n */\n get URL(): string {\n return this.toURLPath()\n }\n\n /** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`).\n *\n * @example\n * ```ts\n * new URLPath('https://petstore.swagger.io/v2/pet').isURL // true\n * new URLPath('/pet/{petId}').isURL // false\n * ```\n */\n get isURL(): boolean {\n try {\n return !!new URL(this.path).href\n } catch {\n return false\n }\n }\n\n /**\n * Converts the OpenAPI path to a TypeScript template literal string.\n *\n * @example\n * new URLPath('/pet/{petId}').template // '`/pet/${petId}`'\n * new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`'\n */\n get template(): string {\n return this.toTemplateString()\n }\n\n /** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}').object\n * // { url: '/pet/:petId', params: { petId: 'petId' } }\n * ```\n */\n get object(): URLObject | string {\n return this.toObject()\n }\n\n /** Returns a map of path parameter names, or `undefined` when the path has no parameters.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}').params // { petId: 'petId' }\n * new URLPath('/pet').params // undefined\n * ```\n */\n get params(): Record<string, string> | undefined {\n return this.toParamsObject()\n }\n\n #transformParam(raw: string): string {\n const param = isValidVarName(raw) ? raw : camelCase(raw)\n return this.#options.casing === 'camelcase' ? camelCase(param) : param\n }\n\n /**\n * Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name.\n */\n #eachParam(fn: (raw: string, param: string) => void): void {\n for (const match of this.path.matchAll(/\\{([^}]+)\\}/g)) {\n const raw = match[1]!\n fn(raw, this.#transformParam(raw))\n }\n }\n\n toObject({ type = 'path', replacer, stringify }: ObjectOptions = {}): URLObject | string {\n const object = {\n url: type === 'path' ? this.toURLPath() : this.toTemplateString({ replacer }),\n params: this.toParamsObject(),\n }\n\n if (stringify) {\n if (type === 'template') {\n return JSON.stringify(object).replaceAll(\"'\", '').replaceAll(`\"`, '')\n }\n\n if (object.params) {\n return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll(\"'\", '').replaceAll(`\"`, '')} }`\n }\n\n return `{ url: '${object.url}' }`\n }\n\n return object\n }\n\n /**\n * Converts the OpenAPI path to a TypeScript template literal string.\n * An optional `replacer` can transform each extracted parameter name before interpolation.\n *\n * @example\n * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`'\n */\n toTemplateString({ prefix = '', replacer }: { prefix?: string; replacer?: (pathParam: string) => string } = {}): string {\n const parts = this.path.split(/\\{([^}]+)\\}/)\n const result = parts\n .map((part, i) => {\n if (i % 2 === 0) return part\n const param = this.#transformParam(part)\n return `\\${${replacer ? replacer(param) : param}}`\n })\n .join('')\n\n return `\\`${prefix}${result}\\``\n }\n\n /**\n * Extracts all `{param}` segments from the path and returns them as a key-value map.\n * An optional `replacer` transforms each parameter name in both key and value positions.\n * Returns `undefined` when no path parameters are found.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}/tag/{tagId}').toParamsObject()\n * // { petId: 'petId', tagId: 'tagId' }\n * ```\n */\n toParamsObject(replacer?: (pathParam: string) => string): Record<string, string> | undefined {\n const params: Record<string, string> = {}\n\n this.#eachParam((_raw, param) => {\n const key = replacer ? replacer(param) : param\n params[key] = key\n })\n\n return Object.keys(params).length > 0 ? params : undefined\n }\n\n /** Converts the OpenAPI path to Express-style colon syntax.\n *\n * @example\n * ```ts\n * new URLPath('/pet/{petId}').toURLPath() // '/pet/:petId'\n * ```\n */\n toURLPath(): string {\n return this.path.replace(/\\{([^}]+)\\}/g, ':$1')\n }\n}\n","import { URLPath } from '@internals/utils'\nimport { ast } from '@kubb/core'\n\nexport type ContentTypeInfo = {\n contentTypes: string[]\n isMultipleContentTypes: boolean\n contentTypeUnion: string\n defaultContentType: string\n hasFormData: boolean\n}\n\nexport type RequestConfigResolver = {\n resolveDataName(node: ast.OperationNode): string\n}\n\nexport type ResponseStatusNameResolver = {\n resolveResponseStatusName(node: ast.OperationNode, statusCode: ast.StatusCode): string\n}\n\nexport type ResponseNameResolver = ResponseStatusNameResolver & {\n resolveResponseName(node: ast.OperationNode): string\n}\n\nexport type OperationTypeNameResolver = RequestConfigResolver &\n ResponseNameResolver & {\n resolvePathParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n resolveQueryParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n resolveHeaderParamsName(node: ast.OperationNode, param: ast.ParameterNode): string\n }\n\nexport type OperationCommentLink = 'pathTemplate' | 'urlPath' | false | ((node: ast.OperationNode) => string | undefined)\n\nexport type BuildOperationCommentsOptions = {\n link?: OperationCommentLink\n linkPosition?: 'beforeDeprecated' | 'afterDeprecated'\n splitLines?: boolean\n}\n\ntype ResponseLike = {\n statusCode: ast.StatusCode | number | string\n}\n\nexport type OperationParameterGroups = Record<ast.ParameterNode['in'], Array<ast.ParameterNode>>\n\nexport type ResolveOperationTypeNameOptions = {\n paramsCasing?: 'camelcase'\n responseStatusNames?: boolean | 'error'\n exclude?: ReadonlyArray<string | undefined>\n order?: 'params-first' | 'body-response-first'\n}\n\nfunction getOperationLink(node: ast.OperationNode, link: OperationCommentLink): string | undefined {\n if (!link) {\n return undefined\n }\n\n if (typeof link === 'function') {\n return link(node)\n }\n\n if (link === 'urlPath') {\n return node.path ? `{@link ${new URLPath(node.path).URL}}` : undefined\n }\n\n return `{@link ${node.path.replaceAll('{', ':').replaceAll('}', '')}}`\n}\n\nexport function getContentTypeInfo(node: ast.OperationNode): ContentTypeInfo {\n const contentTypes = node.requestBody?.content?.map((e) => e.contentType) ?? []\n const isMultipleContentTypes = contentTypes.length > 1\n\n return {\n contentTypes,\n isMultipleContentTypes,\n contentTypeUnion: isMultipleContentTypes ? contentTypes.map((ct) => JSON.stringify(ct)).join(' | ') : '',\n defaultContentType: contentTypes[0] ?? 'application/json',\n hasFormData: contentTypes.some((ct) => ct === 'multipart/form-data'),\n }\n}\n\nexport function buildRequestConfigType(node: ast.OperationNode, resolver: RequestConfigResolver): string {\n const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : undefined\n const { isMultipleContentTypes, contentTypeUnion } = getContentTypeInfo(node)\n const configType = requestName ? `Partial<RequestConfig<${requestName}>>` : 'Partial<RequestConfig>'\n const configProps = ['client?: Client', isMultipleContentTypes ? `contentType?: ${contentTypeUnion}` : undefined].filter(Boolean).join('; ')\n\n return `${configType} & { ${configProps} }`\n}\n\nexport function buildOperationComments(node: ast.OperationNode, options: BuildOperationCommentsOptions = {}): Array<string> {\n const { link = 'pathTemplate', linkPosition = 'afterDeprecated', splitLines = false } = options\n const linkComment = getOperationLink(node, link)\n const comments =\n linkPosition === 'beforeDeprecated'\n ? [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, linkComment, node.deprecated && '@deprecated']\n : [node.description && `@description ${node.description}`, node.summary && `@summary ${node.summary}`, node.deprecated && '@deprecated', linkComment]\n\n const filteredComments = comments.filter((comment): comment is string => Boolean(comment))\n\n if (!splitLines) {\n return filteredComments\n }\n\n return filteredComments.flatMap((text) => text.split(/\\r?\\n/).map((line) => line.trim())).filter((comment): comment is string => Boolean(comment))\n}\n\nexport function getOperationParameters(node: ast.OperationNode, options: { paramsCasing?: 'camelcase' } = {}): OperationParameterGroups {\n const params = ast.caseParams(node.parameters, options.paramsCasing)\n\n return {\n path: params.filter((param) => param.in === 'path'),\n query: params.filter((param) => param.in === 'query'),\n header: params.filter((param) => param.in === 'header'),\n cookie: params.filter((param) => param.in === 'cookie'),\n }\n}\n\nexport function getStatusCodeNumber(statusCode: ast.StatusCode | number | string): number | undefined {\n const code = Number(statusCode)\n\n return Number.isNaN(code) ? undefined : code\n}\n\nexport function isSuccessStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== undefined && code >= 200 && code < 300\n}\n\nexport function isErrorStatusCode(statusCode: ast.StatusCode | number | string): boolean {\n const code = getStatusCodeNumber(statusCode)\n\n return code !== undefined && code >= 400\n}\n\nexport function getSuccessResponses<TResponse extends ResponseLike>(responses: ReadonlyArray<TResponse>): Array<TResponse> {\n return responses.filter((response) => isSuccessStatusCode(response.statusCode))\n}\n\nexport function getOperationSuccessResponses(node: ast.OperationNode): Array<ast.ResponseNode> {\n return getSuccessResponses(node.responses)\n}\n\nexport function getPrimarySuccessResponse(node: ast.OperationNode): ast.ResponseNode | undefined {\n return getOperationSuccessResponses(node)[0]\n}\n\nexport function resolveErrorNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses\n .filter((response) => isErrorStatusCode(response.statusCode))\n .map((response) => resolver.resolveResponseStatusName(node, response.statusCode))\n}\n\nexport function resolveStatusCodeNames(node: ast.OperationNode, resolver: ResponseStatusNameResolver): string[] {\n return node.responses.map((response) => resolver.resolveResponseStatusName(node, response.statusCode))\n}\n\nexport function resolveOperationTypeNames(\n node: ast.OperationNode,\n resolver: OperationTypeNameResolver,\n options: ResolveOperationTypeNameOptions = {},\n): string[] {\n const { path, query, header } = getOperationParameters(node, { paramsCasing: options.paramsCasing })\n const responseStatusNames =\n options.responseStatusNames === 'error'\n ? resolveErrorNames(node, resolver)\n : options.responseStatusNames === false\n ? []\n : resolveStatusCodeNames(node, resolver)\n const exclude = new Set(options.exclude ?? [])\n const paramNames = [\n ...path.map((param) => resolver.resolvePathParamsName(node, param)),\n ...query.map((param) => resolver.resolveQueryParamsName(node, param)),\n ...header.map((param) => resolver.resolveHeaderParamsName(node, param)),\n ]\n const bodyAndResponseNames = [node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : undefined, resolver.resolveResponseName(node)]\n const names =\n options.order === 'body-response-first'\n ? [...bodyAndResponseNames, ...paramNames, ...responseStatusNames]\n : [...paramNames, ...bodyAndResponseNames, ...responseStatusNames]\n\n return names.filter((name): name is string => Boolean(name) && !exclude.has(name))\n}\n\nexport function resolveResponseTypes(node: ast.OperationNode, resolver: ResponseNameResolver): Array<[statusCode: number | 'default', typeName: string]> {\n const types: Array<[number | 'default', string]> = []\n\n for (const response of node.responses) {\n if (response.statusCode === 'default') {\n types.push(['default', resolver.resolveResponseName(node)])\n continue\n }\n\n const code = getStatusCodeNumber(response.statusCode)\n if (code === undefined) {\n continue\n }\n\n types.push([code, isSuccessStatusCode(code) ? resolver.resolveResponseName(node) : resolver.resolveResponseStatusName(node, response.statusCode)])\n }\n\n return types\n}\n\nexport function findSuccessStatusCode(responses: Array<{ statusCode: ast.StatusCode | number | string }>): ast.StatusCode | undefined {\n for (const response of responses) {\n if (isSuccessStatusCode(response.statusCode)) {\n return response.statusCode as ast.StatusCode\n }\n }\n\n return undefined\n}\n","export function buildParamsMapping<TParam extends { name: string }>(\n originalParams: ReadonlyArray<TParam>,\n mappedParams: ReadonlyArray<TParam>,\n): Record<string, string> | undefined {\n const mapping: Record<string, string> = {}\n let hasChanged = false\n\n originalParams.forEach((param, i) => {\n const mappedName = mappedParams[i]?.name ?? param.name\n mapping[param.name] = mappedName\n\n if (param.name !== mappedName) {\n hasChanged = true\n }\n })\n\n return hasChanged ? mapping : undefined\n}\n\nexport function buildTransformedParamsMapping<TParam extends { name: string }>(\n params: ReadonlyArray<TParam>,\n transformName: (name: string) => string,\n): Record<string, string> | undefined {\n if (!params.length) {\n return undefined\n }\n\n return buildParamsMapping(\n params,\n params.map((param) => ({ ...param, name: transformName(param.name) })),\n )\n}\n","import { buildOperationComments, buildTransformedParamsMapping, getOperationParameters } from '@internals/shared'\nimport { camelCase, isValidVarName, URLPath } from '@internals/utils'\nimport { ast } from '@kubb/core'\nimport type { ResolverTs } from '@kubb/plugin-ts'\nimport { functionPrinter } from '@kubb/plugin-ts'\nimport { File, Function } from '@kubb/renderer-jsx'\nimport type { KubbReactNode } from '@kubb/renderer-jsx/types'\nimport type { PluginMcp } from '../types.ts'\n\ntype Props = {\n /**\n * Name of the handler function.\n */\n name: string\n /**\n * AST operation node.\n */\n node: ast.OperationNode\n /**\n * TypeScript resolver for resolving param/data/response type names.\n */\n resolver: ResolverTs\n /**\n * Base URL prepended to every generated request URL.\n */\n baseURL: string | undefined\n /**\n * Return type when calling fetch.\n * - 'data' returns response data only.\n * - 'full' returns the full response object.\n * @default 'data'\n */\n dataReturnType: PluginMcp['resolvedOptions']['client']['dataReturnType']\n /**\n * How to style your params.\n */\n paramsCasing?: PluginMcp['resolvedOptions']['paramsCasing']\n}\n\n/**\n * Generate a remapping statement: `const mappedX = x ? { \"orig\": x.camel, ... } : undefined`\n */\nfunction buildRemappingCode(mapping: Record<string, string>, varName: string, sourceName: string): string {\n const pairs = Object.entries(mapping)\n .map(([orig, camel]) => `\"${orig}\": ${sourceName}.${camel}`)\n .join(', ')\n return `const ${varName} = ${sourceName} ? { ${pairs} } : undefined`\n}\n\nconst declarationPrinter = functionPrinter({ mode: 'declaration' })\n\nexport function McpHandler({ name, node, resolver, baseURL, dataReturnType, paramsCasing }: Props): KubbReactNode {\n const urlPath = new URLPath(node.path)\n const contentType = node.requestBody?.content?.[0]?.contentType\n const isFormData = contentType === 'multipart/form-data'\n\n const { query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing })\n const { path: originalPathParams, query: originalQueryParams, header: originalHeaderParams } = getOperationParameters(node)\n\n const requestName = node.requestBody?.content?.[0]?.schema ? resolver.resolveDataName(node) : undefined\n const responseName = resolver.resolveResponseName(node)\n\n const errorResponses = node.responses.filter((r) => Number(r.statusCode) >= 400).map((r) => resolver.resolveResponseStatusName(node, r.statusCode))\n const errorType = errorResponses.length > 0 ? errorResponses.join(' | ') : 'Error'\n\n const TError = `ResponseErrorConfig<${errorType}>`\n const generics = [responseName, TError, requestName || 'unknown'].filter(Boolean)\n\n const paramsNode = ast.createOperationParams(node, {\n paramsType: 'object',\n pathParamsType: 'inline',\n resolver,\n paramsCasing,\n })\n const baseParamsSignature = declarationPrinter.print(paramsNode) ?? ''\n const paramsSignature = baseParamsSignature\n ? `${baseParamsSignature}, request: RequestHandlerExtra<ServerRequest, ServerNotification>`\n : 'request: RequestHandlerExtra<ServerRequest, ServerNotification>'\n\n const pathParamsMapping = paramsCasing ? buildTransformedParamsMapping(originalPathParams, camelCase) : undefined\n const queryParamsMapping = paramsCasing ? buildTransformedParamsMapping(originalQueryParams, camelCase) : undefined\n const headerParamsMapping = paramsCasing ? buildTransformedParamsMapping(originalHeaderParams, camelCase) : undefined\n\n const contentTypeHeader =\n contentType && contentType !== 'application/json' && contentType !== 'multipart/form-data' ? `'Content-Type': '${contentType}'` : undefined\n const headers = [headerParams.length ? (headerParamsMapping ? '...mappedHeaders' : '...headers') : undefined, contentTypeHeader].filter(Boolean)\n\n const fetchConfig: string[] = []\n fetchConfig.push(`method: ${JSON.stringify(node.method.toUpperCase())}`)\n fetchConfig.push(`url: ${urlPath.template}`)\n if (baseURL) fetchConfig.push(`baseURL: \\`${baseURL}\\``)\n if (queryParams.length) fetchConfig.push(queryParamsMapping ? 'params: mappedParams' : 'params')\n if (requestName) fetchConfig.push(`data: ${isFormData ? 'formData as FormData' : 'requestData'}`)\n if (headers.length) fetchConfig.push(`headers: { ${headers.join(', ')} }`)\n\n const callToolResult =\n dataReturnType === 'data'\n ? `return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(res.data)\n }\n ],\n structuredContent: { data: res.data }\n }`\n : `return {\n content: [\n {\n type: 'text',\n text: JSON.stringify(res)\n }\n ],\n structuredContent: { data: res.data }\n }`\n\n return (\n <File.Source name={name} isExportable isIndexable>\n <Function\n name={name}\n async\n export\n params={paramsSignature}\n JSDoc={{\n comments: buildOperationComments(node),\n }}\n returnType={'Promise<CallToolResult>'}\n >\n {''}\n <br />\n <br />\n {pathParamsMapping &&\n Object.entries(pathParamsMapping)\n .filter(([originalName, camelCaseName]) => originalName !== camelCaseName && isValidVarName(originalName))\n .map(([originalName, camelCaseName]) => `const ${originalName} = ${camelCaseName}`)\n .join('\\n')}\n {pathParamsMapping && (\n <>\n <br />\n <br />\n </>\n )}\n {queryParamsMapping && queryParams.length > 0 && (\n <>\n {buildRemappingCode(queryParamsMapping, 'mappedParams', 'params')}\n <br />\n <br />\n </>\n )}\n {headerParamsMapping && headerParams.length > 0 && (\n <>\n {buildRemappingCode(headerParamsMapping, 'mappedHeaders', 'headers')}\n <br />\n <br />\n </>\n )}\n {requestName && 'const requestData = data'}\n <br />\n {isFormData && requestName && 'const formData = buildFormData(requestData)'}\n <br />\n {`const res = await fetch<${generics.join(', ')}>({ ${fetchConfig.join(', ')} }, request)`}\n <br />\n {callToolResult}\n </Function>\n </File.Source>\n )\n}\n","import type { ast } from '@kubb/core'\n\nexport type ZodParam = {\n name: string\n schemaName: string\n}\n\n/**\n * Render a group param value — compose individual schemas into `z.object({ ... })`,\n * or use a schema name string directly.\n */\nexport function zodGroupExpr(entry: string | Array<ZodParam>): string {\n if (typeof entry === 'string') {\n return entry\n }\n const entries = entry.map((p) => `${JSON.stringify(p.name)}: ${p.schemaName}`)\n return `z.object({ ${entries.join(', ')} })`\n}\n\n/**\n * Convert a SchemaNode type to an inline Zod expression string.\n * Used as fallback when no named zod schema is available for a path parameter.\n */\nexport function zodExprFromSchemaNode(schema: ast.SchemaNode): string {\n let expr: string\n switch (schema.type) {\n case 'enum': {\n // namedEnumValues takes priority over enumValues\n const rawValues: Array<string | number | boolean> = schema.namedEnumValues?.length\n ? schema.namedEnumValues.map((v) => v.value)\n : (schema.enumValues ?? []).filter((v): v is string | number | boolean => v !== null)\n\n if (rawValues.length > 0 && rawValues.every((v) => typeof v === 'string')) {\n expr = `z.enum([${rawValues.map((v) => JSON.stringify(v)).join(', ')}])`\n } else if (rawValues.length > 0) {\n const literals = rawValues.map((v) => `z.literal(${JSON.stringify(v)})`)\n expr = literals.length === 1 ? literals[0]! : `z.union([${literals.join(', ')}])`\n } else {\n expr = 'z.string()'\n }\n break\n }\n case 'integer':\n expr = 'z.coerce.number()'\n break\n case 'number':\n expr = 'z.number()'\n break\n case 'boolean':\n expr = 'z.boolean()'\n break\n case 'array':\n expr = 'z.array(z.unknown())'\n break\n default:\n expr = 'z.string()'\n }\n\n if (schema.nullable) {\n expr = `${expr}.nullable()`\n }\n\n return expr\n}\n","import { getOperationParameters } from '@internals/shared'\nimport { ast } from '@kubb/core'\nimport { functionPrinter } from '@kubb/plugin-ts'\nimport { Const, File, Function } from '@kubb/renderer-jsx'\nimport type { KubbReactNode } from '@kubb/renderer-jsx/types'\nimport type { PluginMcp } from '../types.ts'\nimport type { ZodParam } from '../utils.ts'\nimport { zodExprFromSchemaNode, zodGroupExpr } from '../utils.ts'\n\ntype Props = {\n /**\n * Variable name for the MCP server instance (e.g. 'server').\n */\n name: string\n /**\n * Human-readable server name passed to `new McpServer({ name })`.\n */\n serverName: string\n /**\n * Semantic version string passed to `new McpServer({ version })`.\n */\n serverVersion: string\n /**\n * How to style your params.\n */\n paramsCasing?: PluginMcp['resolvedOptions']['paramsCasing']\n /**\n * Operations to register as MCP tools, each carrying its handler,\n * zod schema, and AST node metadata.\n */\n operations: Array<{\n tool: {\n name: string\n title?: string\n description: string\n }\n mcp: {\n name: string\n file: ast.FileNode\n }\n zod: {\n pathParams: Array<ZodParam>\n /**\n * Query params — individual schemas to compose into `z.object({ ... })`.\n */\n queryParams?: string | Array<ZodParam>\n /**\n * Header params — individual schemas to compose into `z.object({ ... })`.\n */\n headerParams?: string | Array<ZodParam>\n requestName?: string\n responseName?: string\n }\n node: ast.OperationNode\n }>\n}\n\nconst keysPrinter = functionPrinter({ mode: 'keys' })\n\nexport function Server({ name, serverName, serverVersion, paramsCasing, operations }: Props): KubbReactNode {\n return (\n <File.Source name={name} isExportable isIndexable>\n <Const name={'server'} export>\n {`\n new McpServer({\n name: '${serverName}',\n version: '${serverVersion}',\n})\n `}\n </Const>\n\n {operations\n .map(({ tool, mcp, zod, node }) => {\n const { path: pathParams } = getOperationParameters(node, { paramsCasing })\n\n const pathEntries: Array<{ key: string; value: string }> = []\n const otherEntries: Array<{ key: string; value: string }> = []\n\n for (const p of pathParams) {\n const zodParam = zod.pathParams.find((zp) => zp.name === p.name)\n pathEntries.push({ key: p.name, value: zodParam ? zodParam.schemaName : zodExprFromSchemaNode(p.schema) })\n }\n\n if (zod.requestName) {\n otherEntries.push({ key: 'data', value: zod.requestName })\n }\n\n if (zod.queryParams) {\n otherEntries.push({ key: 'params', value: zodGroupExpr(zod.queryParams) })\n }\n\n if (zod.headerParams) {\n otherEntries.push({ key: 'headers', value: zodGroupExpr(zod.headerParams) })\n }\n\n otherEntries.sort((a, b) => a.key.localeCompare(b.key))\n const entries = [...pathEntries, ...otherEntries]\n\n const paramsNode = entries.length\n ? ast.createFunctionParameters({\n params: [\n ast.createParameterGroup({\n properties: entries.map((e) => ast.createFunctionParameter({ name: e.key, optional: false })),\n }),\n ],\n })\n : undefined\n\n const destructured = paramsNode ? (keysPrinter.print(paramsNode) ?? '') : ''\n const inputSchema = entries.length ? `{ ${entries.map((e) => `${e.key}: ${e.value}`).join(', ')} }` : undefined\n const outputSchema = zod.responseName\n\n const config = [\n tool.title ? `title: ${JSON.stringify(tool.title)}` : null,\n `description: ${JSON.stringify(tool.description)}`,\n outputSchema ? `outputSchema: { data: ${outputSchema} }` : null,\n ]\n .filter(Boolean)\n .join(',\\n ')\n\n if (inputSchema) {\n return `\nserver.registerTool(${JSON.stringify(tool.name)}, {\n ${config},\n inputSchema: ${inputSchema},\n}, async (${destructured}, request) => {\n return ${mcp.name}(${destructured}, request)\n})\n `\n }\n\n return `\nserver.registerTool(${JSON.stringify(tool.name)}, {\n ${config},\n}, async (request) => {\n return ${mcp.name}(request)\n})\n `\n })\n .filter(Boolean)}\n\n <Function name=\"startServer\" async export>\n {`try {\n const transport = new StdioServerTransport()\n await server.connect(transport)\n\n } catch (error) {\n console.error('Failed to start server:', error)\n process.exit(1)\n }`}\n </Function>\n </File.Source>\n )\n}\n","import path from 'node:path'\nimport { resolveOperationTypeNames } from '@internals/shared'\nimport { defineGenerator } from '@kubb/core'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { File, jsxRenderer } from '@kubb/renderer-jsx'\nimport { McpHandler } from '../components/McpHandler.tsx'\nimport type { PluginMcp } from '../types.ts'\n\nexport const mcpGenerator = defineGenerator<PluginMcp>({\n name: 'mcp',\n renderer: jsxRenderer,\n operation(node, ctx) {\n const { resolver, driver, root } = ctx\n const { output, client, paramsCasing, group } = ctx.options\n\n const pluginTs = driver.getPlugin(pluginTsName)\n\n if (!pluginTs) {\n return null\n }\n\n const tsResolver = driver.getResolver(pluginTsName)\n\n const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing, responseStatusNames: 'error' })\n\n const meta = {\n name: resolver.resolveHandlerName(node),\n file: resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),\n fileTs: tsResolver.resolveFile(\n { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },\n {\n root,\n output: pluginTs.options?.output ?? output,\n group: pluginTs.options?.group,\n },\n ),\n } as const\n\n return (\n <File baseName={meta.file.baseName} path={meta.file.path} meta={meta.file.meta}>\n {meta.fileTs && importedTypeNames.length > 0 && (\n <File.Import name={Array.from(new Set(importedTypeNames)).sort()} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />\n )}\n <File.Import name={['CallToolResult', 'ServerNotification', 'ServerRequest']} path={'@modelcontextprotocol/sdk/types'} isTypeOnly />\n <File.Import name={['RequestHandlerExtra']} path={'@modelcontextprotocol/sdk/shared/protocol'} isTypeOnly />\n <File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />\n {client.importPath ? (\n <>\n <File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={client.importPath} isTypeOnly />\n <File.Import name={'fetch'} path={client.importPath} />\n {client.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={client.importPath} isTypeOnly />}\n </>\n ) : (\n <>\n <File.Import\n name={['Client', 'RequestConfig', 'ResponseErrorConfig']}\n root={meta.file.path}\n path={path.resolve(root, '.kubb/fetch.ts')}\n isTypeOnly\n />\n <File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />\n {client.dataReturnType === 'full' && (\n <File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />\n )}\n </>\n )}\n\n <McpHandler\n name={meta.name}\n node={node}\n resolver={tsResolver}\n baseURL={client.baseURL}\n dataReturnType={client.dataReturnType || 'data'}\n paramsCasing={paramsCasing}\n />\n </File>\n )\n },\n})\n","import path from 'node:path'\nimport { findSuccessStatusCode, getOperationParameters } from '@internals/shared'\nimport { defineGenerator } from '@kubb/core'\nimport { pluginZodName } from '@kubb/plugin-zod'\nimport { File, jsxRenderer } from '@kubb/renderer-jsx'\nimport { Server } from '../components/Server.tsx'\nimport type { PluginMcp } from '../types.ts'\n\n/**\n * Default v5 server generator for `@kubb/plugin-mcp`.\n *\n * Uses individual zod schemas for each param (e.g. `createPetsPathUuidSchema`, `createPetsQueryOffsetSchema`)\n * and `resolveResponseStatusName` for per-status response schemas.\n * Query and header params are composed into `z.object({ ... })` from individual schemas.\n */\nexport const serverGenerator = defineGenerator<PluginMcp>({\n name: 'operations',\n renderer: jsxRenderer,\n operations(nodes, ctx) {\n const { adapter, config, resolver, plugin, driver, root } = ctx\n const { output, paramsCasing, group } = ctx.options\n\n const pluginZod = driver.getPlugin(pluginZodName)\n\n if (!pluginZod) {\n return\n }\n\n const zodResolver = driver.getResolver(pluginZodName)\n\n const name = 'server'\n const serverFilePath = path.resolve(root, output.path, 'server.ts')\n const serverFile = {\n baseName: 'server.ts' as const,\n path: serverFilePath,\n meta: { pluginName: plugin.name },\n }\n\n const jsonFilePath = path.resolve(root, output.path, '.mcp.json')\n const jsonFile = {\n baseName: '.mcp.json' as const,\n path: jsonFilePath,\n meta: { pluginName: plugin.name },\n }\n\n const operationsMapped = nodes.map((node) => {\n const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing })\n\n const mcpFile = resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group })\n\n const zodFile = zodResolver.resolveFile(\n { name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },\n {\n root,\n output: pluginZod.options?.output ?? output,\n group: pluginZod.options?.group,\n },\n )\n\n const requestName = node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName(node) : undefined\n const successStatus = findSuccessStatusCode(node.responses)\n const responseName = successStatus ? zodResolver.resolveResponseStatusName(node, successStatus) : undefined\n\n const resolveParams = (params: typeof pathParams) => params.map((p) => ({ name: p.name, schemaName: zodResolver.resolveParamName(node, p) }))\n\n return {\n tool: {\n name: node.operationId,\n title: node.summary || undefined,\n description: node.description || `Make a ${node.method.toUpperCase()} request to ${node.path}`,\n },\n mcp: {\n name: resolver.resolveHandlerName(node),\n file: mcpFile,\n },\n zod: {\n pathParams: resolveParams(pathParams),\n queryParams: queryParams.length ? resolveParams(queryParams) : undefined,\n headerParams: headerParams.length ? resolveParams(headerParams) : undefined,\n requestName,\n responseName,\n file: zodFile,\n },\n node: node,\n }\n })\n\n const imports = operationsMapped.flatMap(({ mcp, zod }) => {\n const zodNames = [\n ...zod.pathParams.map((p) => p.schemaName),\n ...(zod.queryParams ?? []).map((p) => p.schemaName),\n ...(zod.headerParams ?? []).map((p) => p.schemaName),\n zod.requestName,\n zod.responseName,\n ].filter((name): name is string => Boolean(name))\n\n const uniqueNames = [...new Set(zodNames)].sort()\n\n return [\n <File.Import key={mcp.name} name={[mcp.name]} root={serverFile.path} path={mcp.file.path} />,\n uniqueNames.length > 0 && <File.Import key={`zod-${mcp.name}`} name={uniqueNames} root={serverFile.path} path={zod.file.path} />,\n ].filter(Boolean)\n })\n\n return (\n <>\n <File\n baseName={serverFile.baseName}\n path={serverFile.path}\n meta={serverFile.meta}\n banner={resolver.resolveBanner(adapter.inputNode, { output, config })}\n footer={resolver.resolveFooter(adapter.inputNode, { output, config })}\n >\n <File.Import name={['McpServer']} path={'@modelcontextprotocol/sdk/server/mcp'} />\n <File.Import name={['z']} path={'zod'} />\n <File.Import name={['StdioServerTransport']} path={'@modelcontextprotocol/sdk/server/stdio'} />\n\n {imports}\n <Server\n name={name}\n serverName={adapter.inputNode?.meta?.title ?? 'server'}\n serverVersion={adapter.inputNode?.meta?.version ?? '0.0.0'}\n paramsCasing={paramsCasing}\n operations={operationsMapped}\n />\n </File>\n\n <File baseName={jsonFile.baseName} path={jsonFile.path} meta={jsonFile.meta}>\n <File.Source name={name}>\n {`\n {\n \"mcpServers\": {\n \"${adapter.inputNode?.meta?.title || 'server'}\": {\n \"type\": \"stdio\",\n \"command\": \"npx\",\n \"args\": [\"tsx\", \"${path.relative(path.dirname(jsonFile.path), serverFile.path)}\"]\n }\n }\n }\n `}\n </File.Source>\n </File>\n </>\n )\n },\n})\n","import { camelCase } from '@internals/utils'\nimport { defineResolver } from '@kubb/core'\nimport type { PluginMcp } from '../types.ts'\n\n/**\n * Naming convention resolver for MCP plugin.\n *\n * Provides default naming helpers using camelCase with a `handler` suffix for functions.\n *\n * @example\n * `resolverMcp.default('addPet', 'function') // → 'addPetHandler'`\n */\nexport const resolverMcp = defineResolver<PluginMcp>(() => ({\n name: 'default',\n pluginName: 'plugin-mcp',\n default(name, type) {\n if (type === 'file') {\n return camelCase(name, { isFile: true })\n }\n return camelCase(name, { suffix: 'handler' })\n },\n resolveName(name) {\n return this.default(name, 'function')\n },\n resolvePathName(name, type) {\n return this.default(name, type)\n },\n resolveHandlerName(node) {\n return this.resolveName(node.operationId)\n },\n}))\n","import path from 'node:path'\nimport { camelCase } from '@internals/utils'\n\nimport { ast, definePlugin, type Group } from '@kubb/core'\nimport { pluginClientName } from '@kubb/plugin-client'\nimport { source as axiosClientSource } from '@kubb/plugin-client/templates/clients/axios.source'\nimport { source as fetchClientSource } from '@kubb/plugin-client/templates/clients/fetch.source'\nimport { source as configSource } from '@kubb/plugin-client/templates/config.source'\nimport { pluginTsName } from '@kubb/plugin-ts'\nimport { pluginZodName } from '@kubb/plugin-zod'\nimport { mcpGenerator } from './generators/mcpGenerator.tsx'\nimport { serverGenerator } from './generators/serverGenerator.tsx'\nimport { resolverMcp } from './resolvers/resolverMcp.ts'\nimport type { PluginMcp } from './types.ts'\n\nexport const pluginMcpName = 'plugin-mcp' satisfies PluginMcp['name']\n\nexport const pluginMcp = definePlugin<PluginMcp>((options) => {\n const {\n output = { path: 'mcp', barrelType: 'named' },\n group,\n exclude = [],\n include,\n override = [],\n paramsCasing,\n client,\n resolver: userResolver,\n transformer: userTransformer,\n generators: userGenerators = [],\n } = options\n\n const clientName = client?.client ?? 'axios'\n const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : undefined)\n\n const groupConfig = group\n ? ({\n ...group,\n name: group.name\n ? group.name\n : (ctx: { group: string }) => {\n if (group.type === 'path') {\n return `${ctx.group.split('/')[1]}`\n }\n return `${camelCase(ctx.group)}Requests`\n },\n } satisfies Group)\n : undefined\n\n return {\n name: pluginMcpName,\n options,\n dependencies: [pluginTsName, pluginZodName],\n hooks: {\n 'kubb:plugin:setup'(ctx) {\n const resolver = userResolver ? { ...resolverMcp, ...userResolver } : resolverMcp\n\n ctx.setOptions({\n output,\n exclude,\n include,\n override,\n group: groupConfig,\n paramsCasing,\n client: {\n client: clientName,\n clientType: client?.clientType ?? 'function',\n importPath: clientImportPath,\n dataReturnType: client?.dataReturnType ?? 'data',\n bundle: client?.bundle,\n baseURL: client?.baseURL,\n paramsCasing: client?.paramsCasing,\n },\n resolver,\n })\n ctx.setResolver(resolver)\n if (userTransformer) {\n ctx.setTransformer(userTransformer)\n }\n ctx.addGenerator(mcpGenerator)\n ctx.addGenerator(serverGenerator)\n for (const gen of userGenerators) {\n ctx.addGenerator(gen)\n }\n\n const root = path.resolve(ctx.config.root, ctx.config.output.path)\n const hasClientPlugin = ctx.config.plugins?.some((p) => p.name === pluginClientName)\n\n if (client?.bundle && !hasClientPlugin && !clientImportPath) {\n ctx.injectFile({\n baseName: 'fetch.ts',\n path: path.resolve(root, '.kubb/fetch.ts'),\n sources: [\n ast.createSource({\n name: 'fetch',\n nodes: [ast.createText(clientName === 'fetch' ? fetchClientSource : axiosClientSource)],\n isExportable: true,\n isIndexable: true,\n }),\n ],\n })\n }\n\n if (!hasClientPlugin) {\n ctx.injectFile({\n baseName: 'config.ts',\n path: path.resolve(root, '.kubb/config.ts'),\n sources: [\n ast.createSource({\n name: 'config',\n nodes: [ast.createText(configSource)],\n isExportable: false,\n isIndexable: false,\n }),\n ],\n })\n }\n },\n },\n }\n})\n\nexport default pluginMcp\n"],"mappings":"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"}
package/extension.yaml ADDED
@@ -0,0 +1,463 @@
1
+ $schema: https://kubb.dev/schemas/extension.json
2
+ kind: plugin
3
+ id: plugin-mcp
4
+ name: MCP
5
+ description: Generate Model Context Protocol (MCP) servers from OpenAPI specifications for AI assistants to call your API.
6
+ category: ai
7
+ type: official
8
+ npmPackage: '@kubb/plugin-mcp'
9
+ docsPath: /plugins/plugin-mcp
10
+ repo: https://github.com/kubb-labs/plugins
11
+ maintainers:
12
+ - name: Stijn Van Hulle
13
+ github: stijnvanhulle
14
+ compatibility:
15
+ kubb: '>=5.0.0'
16
+ node: '>=22'
17
+ tags:
18
+ - mcp
19
+ - model-context-protocol
20
+ - ai
21
+ - claude
22
+ - llm
23
+ - codegen
24
+ - openapi
25
+ dependencies:
26
+ - plugin-ts
27
+ - plugin-client
28
+ - plugin-zod
29
+ resources:
30
+ documentation: https://kubb.dev/plugins/plugin-mcp
31
+ repository: https://github.com/kubb-labs/plugins
32
+ issues: https://github.com/kubb-labs/plugins/issues
33
+ changelog: https://github.com/kubb-labs/plugins/blob/main/packages/plugin-mcp/CHANGELOG.md
34
+ codesandbox: https://codesandbox.io/p/github/kubb-labs/plugins/main/examples/mcp
35
+ featured: false
36
+ icon:
37
+ light: https://kubb.dev/feature/mcp-light.svg
38
+ dark: https://kubb.dev/feature/mcp-dark.svg
39
+ intro: |
40
+ # @kubb/plugin-mcp
41
+
42
+ Generate [Model Context Protocol](https://modelcontextprotocol.io/introduction) servers from your OpenAPI schema. AI assistants like Claude can now call your API through conversational interfaces.
43
+
44
+ ```mermaid
45
+ graph TD
46
+ A[Kubb<br/>Generates code from OpenAPI] --> B[MCP Server<br/>Handles tool calls]
47
+ B --> C[Claude<br/>Conversational AI]
48
+ C -->|Sends tool request| B
49
+ B -->|Uses generated code| A
50
+ ```
51
+ notes:
52
+ - type: tip
53
+ body: |
54
+ See [Setup Claude with Kubb](https://modelcontextprotocol.io/docs/tools/claude-desktop) for configuration instructions.
55
+ options:
56
+ - name: output
57
+ type: Output
58
+ required: false
59
+ default: "{ path: 'mcp', barrel: { type: 'named' } }"
60
+ description: Specify the export location for the files and define the behavior of the output.
61
+ properties:
62
+ - name: path
63
+ type: string
64
+ required: true
65
+ description: Output directory or file for the generated code, relative to the global `output.path`.
66
+ tip: |
67
+ if `output.path` is a file, `group` cannot be used.
68
+ default: "'mcp'"
69
+ - name: barrel
70
+ type: "{ type: 'named' | 'all', nested?: boolean } | false"
71
+ required: false
72
+ default: "{ type: 'named' }"
73
+ description: "Configure barrel file export strategy. Use `type` to control named vs. wildcard exports; set `nested: true` to generate hierarchical barrels in subdirectories."
74
+ examples:
75
+ - name: all
76
+ files:
77
+ - lang: typescript
78
+ code: |
79
+ export * from './gen/petService.ts'
80
+ twoslash: false
81
+ - name: named
82
+ files:
83
+ - lang: typescript
84
+ code: |
85
+ export { PetService } from './gen/petService.ts'
86
+ twoslash: false
87
+ - name: 'false'
88
+ files:
89
+ - lang: typescript
90
+ code: ''
91
+ twoslash: false
92
+ - name: banner
93
+ type: 'string | ((node: RootNode) => string)'
94
+ required: false
95
+ description: Add a banner comment at the top of every generated file. Accepts a static string or a function that receives the `RootNode` and returns a string.
96
+ - name: footer
97
+ type: 'string | ((node: RootNode) => string)'
98
+ required: false
99
+ description: Add a footer comment at the end of every generated file. Accepts a static string or a function that receives the `RootNode` and returns a string.
100
+ - name: override
101
+ type: boolean
102
+ required: false
103
+ default: 'false'
104
+ description: Whether Kubb overrides existing external files that can be generated if they already exist.
105
+ - name: resolver
106
+ type: Partial<ResolverMcp> & ThisType<ResolverMcp>
107
+ required: false
108
+ description: |
109
+ A single resolver that overrides the naming and path-resolution conventions. Each method you provide replaces the corresponding built-in one. When a method returns `null` or `undefined`, the resolver's result is used as the fallback, so you only need to supply the methods you want to change.
110
+
111
+ `this` inside each method is bound to the **full** resolver, so you can call other resolver methods (e.g. `this.default(name, 'function')`) without losing context.
112
+ body: |
113
+ Each plugin ships a built-in resolver:
114
+
115
+ | Plugin | Default resolver |
116
+ | --- | --- |
117
+ | `@kubb/plugin-ts` | `resolverTs` |
118
+ | `@kubb/plugin-zod` | `resolverZod` |
119
+ | `@kubb/plugin-cypress` | `resolverCypress` |
120
+ | `@kubb/plugin-mcp` | `resolverMcp` |
121
+ codeBlock:
122
+ lang: typescript
123
+ title: Custom resolver (plugin-mcp example)
124
+ code: |
125
+ import { pluginMcp } from '@kubb/plugin-mcp'
126
+
127
+ pluginMcp({
128
+ resolver: {
129
+ resolveName(name) {
130
+ return `Mcp${this.default(name, 'function')}`
131
+ },
132
+ },
133
+ })
134
+ tip: |
135
+ Use `resolver` for fine-grained control over naming conventions.
136
+ - name: group
137
+ type: Group
138
+ required: false
139
+ description: |
140
+ Grouping combines files in a folder based on a specific `type`.
141
+ examples:
142
+ - name: kubb.config.ts
143
+ files:
144
+ - lang: typescript
145
+ code: |
146
+ group: {
147
+ type: 'tag',
148
+ name({ group }) {
149
+ return `${group}Controller`
150
+ }
151
+ }
152
+ twoslash: false
153
+ body: |
154
+ With the configuration above, the generator emits:
155
+
156
+ ```text
157
+ .
158
+ ├── src/
159
+ │ └── petController/
160
+ │ │ ├── addPet.ts
161
+ │ │ └── getPet.ts
162
+ │ └── storeController/
163
+ │ ├── createStore.ts
164
+ │ └── getStoreById.ts
165
+ ├── petStore.yaml
166
+ ├── kubb.config.ts
167
+ └── package.json
168
+ ```
169
+ properties:
170
+ - name: type
171
+ type: "'tag'"
172
+ required: true
173
+ description: Specify the property to group files by. Required when `group` is defined.
174
+ note: |
175
+ `Required: true*` means this is required only when the `group` option is used. The `group` option itself is optional.
176
+ body: |
177
+ - `'tag'`: Uses the first tag from `operation.getTags().at(0)?.name`
178
+ - name: name
179
+ type: '(context: GroupContext) => string'
180
+ required: false
181
+ default: (ctx) => `${ctx.group}Requests`
182
+ description: Return the name of a group based on the group name. This is used for file and identifier generation.
183
+ - name: paramsCasing
184
+ type: "'camelcase'"
185
+ required: false
186
+ description: Transform parameter names to camelCase in generated MCP handlers.
187
+ important: |
188
+ When using `paramsCasing`, ensure that `@kubb/plugin-ts` also has the same `paramsCasing` setting. This option automatically maps transformed parameter names back to their original API names in HTTP requests.
189
+ body: |
190
+ - `'camelcase'` transforms parameter names to camelCase.
191
+ examples:
192
+ - name: With paramsCasing camelcase
193
+ files:
194
+ - lang: typescript
195
+ code: |
196
+ // Handler uses camelCase parameters
197
+ export async function findPetsByStatusHandler({
198
+ stepId // ✓ camelCase
199
+ }: {
200
+ stepId: FindPetsByStatusPathParams['stepId']
201
+ }): Promise<Promise<CallToolResult>> {
202
+ // Automatically maps back to original name
203
+ const step_id = stepId
204
+
205
+ const res = await fetch({
206
+ method: 'GET',
207
+ url: `/pet/findByStatus/${step_id}`, // Uses original API name
208
+ ...
209
+ })
210
+ ...
211
+ }
212
+ twoslash: false
213
+ - name: Without paramsCasing
214
+ files:
215
+ - lang: typescript
216
+ code: |
217
+ // Handler uses original API naming
218
+ export async function findPetsByStatusHandler({
219
+ step_id // Original naming
220
+ }: {
221
+ step_id: FindPetsByStatusPathParams['step_id']
222
+ }): Promise<Promise<CallToolResult>> {
223
+ const res = await fetch({
224
+ method: 'GET',
225
+ url: `/pet/findByStatus/${step_id}`,
226
+ ...
227
+ })
228
+ ...
229
+ }
230
+ twoslash: false
231
+ - name: client
232
+ type: ClientImportPath & { clientType?, dataReturnType?, baseURL?, bundle?, paramsCasing? }
233
+ required: false
234
+ description: Client configuration for HTTP request generation, including client type, data return type, base URL, and bundling options.
235
+ properties:
236
+ - name: importPath
237
+ type: string
238
+ required: false
239
+ description: Path to the client used for API calls. Supports both relative and absolute paths.
240
+ details:
241
+ - title: When to use `importPath`
242
+ body: |
243
+ Use `importPath` when you want to:
244
+
245
+ - **Customize the HTTP client**: Provide your own client implementation with custom configurations (e.g., baseURL, headers, interceptors)
246
+ - **Add authentication**: Include authentication tokens or other security mechanisms in your client
247
+ - **Override default behavior**: Replace the default Kubb client with your own implementation
248
+ - title: Default behavior
249
+ body: |
250
+ When `importPath` is not specified:
251
+
252
+ - If `bundle: false` (default): Uses `@kubb/plugin-client/clients/${client}` where client is either `axios` or `fetch`.
253
+ - If `bundle: true`: Bundles the client into `.kubb/fetch.ts`.
254
+ - title: Import structure
255
+ body: 'Generated code imports the client as a default import and the runtime types as named type imports:'
256
+ codeBlock:
257
+ lang: typescript
258
+ code: |-
259
+ /**
260
+ * Generated by Kubb (https://kubb.dev/).
261
+ * Do not edit manually.
262
+ */
263
+ import client from '${client.importPath}'
264
+ import type { RequestConfig, ResponseErrorConfig } from '${client.importPath}'
265
+ // ... rest of generated file
266
+ important: |
267
+ When using `importPath` with query plugins such as `@kubb/plugin-react-query` or `@kubb/plugin-vue-query`, the generated hooks also import a `Client` type alongside `RequestConfig` and `ResponseErrorConfig` from the custom module. Your custom client module **must** export all three types — if any is missing, TypeScript will report an unresolvable import error.
268
+ codeBlock:
269
+ lang: typescript
270
+ title: client.ts
271
+ code: |
272
+ export type RequestConfig<TData = unknown> = {
273
+ url?: string
274
+ method: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE'
275
+ params?: object
276
+ data?: TData | FormData
277
+ responseType?: 'arraybuffer' | 'blob' | 'document' | 'json' | 'text' | 'stream'
278
+ signal?: AbortSignal
279
+ headers?: HeadersInit
280
+ }
281
+
282
+ export type ResponseConfig<TData = unknown> = {
283
+ data: TData
284
+ status: number
285
+ statusText: string
286
+ }
287
+
288
+ export type ResponseErrorConfig<TError = unknown> = TError
289
+
290
+ // The Client type alias is required when using query plugins
291
+ export type Client = <TData, _TError = unknown, TVariables = unknown>(
292
+ config: RequestConfig<TVariables>
293
+ ) => Promise<ResponseConfig<TData>>
294
+
295
+ export const client: Client = async (config) => { /* ... */ }
296
+ export default client
297
+ examples:
298
+ - name: kubb.config.ts
299
+ files:
300
+ - lang: typescript
301
+ code: |
302
+ import { defineConfig } from 'kubb'
303
+ import { pluginClient } from '@kubb/plugin-client'
304
+
305
+ export default defineConfig({
306
+ // ...
307
+ plugins: [
308
+ pluginClient({
309
+ importPath: './src/client.ts', // Path to your custom client
310
+ }),
311
+ ],
312
+ })
313
+ twoslash: false
314
+ tip: |
315
+ Learn more about defining a custom client [here](https://kubb.dev/plugins/plugin-client#importpath).
316
+ - name: dataReturnType
317
+ type: "'data' | 'full'"
318
+ required: false
319
+ default: "'data'"
320
+ description: |
321
+ Return type used when calling the client.
322
+
323
+ - `'data'` returns `ResponseConfig['data']`.
324
+ - `'full'` returns the full `ResponseConfig`.
325
+ examples:
326
+ - name: data
327
+ files:
328
+ - lang: typescript
329
+ code: |
330
+ export async function getPetById<TData>(
331
+ petId: GetPetByIdPathParams,
332
+ ): Promise<ResponseConfig<TData>['data']> {
333
+ ...
334
+ }
335
+ twoslash: false
336
+ - name: full
337
+ files:
338
+ - lang: typescript
339
+ code: |
340
+ export async function getPetById<TData>(
341
+ petId: GetPetByIdPathParams,
342
+ ): Promise<ResponseConfig<TData>> {
343
+ ...
344
+ }
345
+ twoslash: false
346
+ - name: baseURL
347
+ type: string
348
+ required: false
349
+ description: Sets a custom base URL for all generated calls. When not set, the base URL is automatically taken from the OAS spec via the adapter (e.g. the `servers[0].url` field).
350
+ - name: include
351
+ type: Array<Include>
352
+ required: false
353
+ description: Array containing include parameters to include tags, operations, methods, paths, or content types.
354
+ codeBlock:
355
+ lang: typescript
356
+ title: Include
357
+ code: |
358
+ export type Include = {
359
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
360
+ pattern: string | RegExp
361
+ }
362
+ - name: exclude
363
+ type: Array<Exclude>
364
+ required: false
365
+ description: Array containing exclude parameters to exclude or skip tags, operations, methods, paths, or content types.
366
+ codeBlock:
367
+ lang: typescript
368
+ title: Exclude
369
+ code: |
370
+ export type Exclude = {
371
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
372
+ pattern: string | RegExp
373
+ }
374
+ - name: override
375
+ type: Array<Override>
376
+ required: false
377
+ description: Array containing override parameters to override `options` based on tags, operations, methods, paths, or content types.
378
+ codeBlock:
379
+ lang: typescript
380
+ title: Override
381
+ code: |
382
+ export type Override = {
383
+ type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
384
+ pattern: string | RegExp
385
+ options: PluginOptions
386
+ }
387
+ - name: generators
388
+ type: Array<Generator<PluginMcp>>
389
+ required: false
390
+ experimental: true
391
+ description: |
392
+ Define additional generators next to the built-in generators.
393
+
394
+ See [Generators](https://kubb.dev/docs/5.x/guides/creating-plugins) for more information on how to use generators.
395
+ - name: transformer
396
+ type: Visitor
397
+ required: false
398
+ description: |
399
+ A single AST visitor applied to every node before code is printed. Each method you provide replaces the corresponding built-in one. When a method returns `null` or `undefined`, the preset transformer's result is used as the fallback — so you only need to supply the methods you want to change.
400
+
401
+ Visitor methods receive the node and a context object. Return a modified node to replace it, or return `undefined`/`void` to leave it unchanged.
402
+ examples:
403
+ - name: Strip descriptions before printing
404
+ files:
405
+ - lang: typescript
406
+ code: |
407
+ import { pluginTs } from '@kubb/plugin-ts'
408
+
409
+ pluginTs({
410
+ transformer: {
411
+ schema(node) {
412
+ return { ...node, description: undefined }
413
+ },
414
+ },
415
+ })
416
+ twoslash: false
417
+ - name: Prefix every operationId
418
+ files:
419
+ - lang: typescript
420
+ code: |
421
+ import { pluginTs } from '@kubb/plugin-ts'
422
+
423
+ pluginTs({
424
+ transformer: {
425
+ operation(node) {
426
+ return { ...node, operationId: `api_${node.operationId}` }
427
+ },
428
+ },
429
+ })
430
+ twoslash: false
431
+ tip: |
432
+ Use `transformer` to rewrite node properties before printing. For output naming customization, use `resolver` instead.
433
+ examples:
434
+ - name: kubb.config.ts
435
+ files:
436
+ - lang: typescript
437
+ code: |
438
+ import { defineConfig } from 'kubb'
439
+ import { pluginTs } from '@kubb/plugin-ts'
440
+ import { pluginClient } from '@kubb/plugin-client'
441
+ import { pluginZod } from '@kubb/plugin-zod'
442
+ import { pluginMcp } from '@kubb/plugin-mcp'
443
+
444
+ export default defineConfig({
445
+ input: { path: './petStore.yaml' },
446
+ output: { path: './src/gen' },
447
+ plugins: [
448
+ pluginTs(),
449
+ pluginClient(),
450
+ pluginZod(),
451
+ pluginMcp({
452
+ output: { path: 'mcp', barrel: { type: 'named' } },
453
+ client: {
454
+ baseURL: 'https://petstore.swagger.io/v2',
455
+ },
456
+ group: {
457
+ type: 'tag',
458
+ name: ({ group }) => `${group}Handlers`,
459
+ },
460
+ }),
461
+ ],
462
+ })
463
+ twoslash: false