Beta You're reading the docs for Kubb v5, which is currently in beta. View the stable v4 docs
Skip to content

Migration: @kubb/plugin-mcp

Part of the v4 → v5 migration guide. For the full option reference, see @kubb/plugin-mcp.

resolver.resolveName replaces transformers.name, and the generators option is gone.

client selects a registered client plugin

In v4, client was an object that configured a bundled client: clientType, dataReturnType, baseURL, bundle, importPath, and paramsCasing. v5 drops all of those. The handlers now call a registered client plugin, so client is a single string that picks which one: 'axios' or 'fetch'. Register @kubb/plugin-axios or @kubb/plugin-fetch in plugins, and set baseURL there instead of on pluginMcp. When exactly one client plugin is registered, Kubb auto-detects it and the string is optional.

pluginMcp also depends on @kubb/plugin-ts and @kubb/plugin-zod, so register both alongside the client plugin.

typescript
import { defineConfig } from '@kubb/core'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginZod } from '@kubb/plugin-zod'
import { pluginMcp } from '@kubb/plugin-mcp'

export default defineConfig({
  input: { path: './petStore.yaml' },
  output: { path: './src/gen' },
  plugins: [
    pluginTs(),
    pluginZod(),
    pluginMcp({
      client: {
        client: 'fetch',
        baseURL: 'https://petstore.swagger.io/v2',
      },
    }),
  ],
})
typescript
import { defineConfig } from 'kubb'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginZod } from '@kubb/plugin-zod'
import { pluginFetch } from '@kubb/plugin-fetch'
import { pluginMcp } from '@kubb/plugin-mcp'

export default defineConfig({
  input: { path: './petStore.yaml' },
  output: { path: './src/gen' },
  plugins: [
    pluginTs(),
    pluginZod(),
    pluginFetch({ baseURL: 'https://petstore.swagger.io/v2' }),
    pluginMcp({ client: 'fetch' }),
  ],
})

Removed: paramsCasing

v4 kubb.config.ts
typescript
pluginMcp({ paramsCasing: 'camelcase' })

Parameter properties in the generated handlers are now always camelCase, including the client.paramsCasing sub-option, so drop both. The HTTP layer still uses the original spec names, and Kubb writes the mapping for you.

Generated output

Each handler now takes a second argument, the MCP RequestHandlerExtra object, so it can read the request context. The handler no longer builds the request inline. Instead it calls the named operation from the registered client plugin (addPet here) with a single grouped { path, query, headers, body } config object, and reads res.data.

Generated output
diff
import type { CallToolResult } from '@modelcontextprotocol/sdk/types'
import type { CallToolResult, ServerNotification, ServerRequest } from '@modelcontextprotocol/sdk/types'
import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol'
import { addPet } from './clients/addPet'

export async function addPetHandler({ data }: { data: AddPetMutationRequest }): Promise<CallToolResult> {
export async function addPetHandler(
  { body }: AddPetRequestConfig,
  request: RequestHandlerExtra<ServerRequest, ServerNotification>,
): Promise<CallToolResult> {
  const res = await fetch<AddPetMutationResponse, ResponseErrorConfig<AddPet405>, AddPetMutationRequest>({
    method: 'POST',
    url: '/pet',
    baseURL: 'https://petstore.swagger.io/v2',
    data,
  })
  const res = await addPet({ body })
  ...
}