Open Studio
Migration

Migration: @kubb/plugin-mcp

Changes for @kubb/plugin-mcp when migrating from Kubb v4 to v5.

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

resolver.name 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, paramsCasing). In v5 it is a string that names a registered client plugin. See Query and MCP plugins select a client for the shared rules, then register @kubb/plugin-axios or @kubb/plugin-fetch in plugins and set baseURL there instead of on pluginMcp.

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: './petStore.yaml',
  output: { path: './src/gen' },
  plugins: [
    pluginTs(),
    pluginZod(),
    pluginMcp({
      client: {
        client: 'fetch',
        baseURL: 'https://petstore.swagger.io/v2',
      },
    }),
  ],
})
typescript
import { defineConfig } from 'kubb/config'
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: './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 come from the @kubb/plugin-ts *Options type, so they match the names in your OpenAPI document. The client.paramsCasing sub-option is gone too, so drop both.

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 }: AddPetOptions,
  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 })
  ...
}