Set up Claude with Kubb#
![]()
Kubb and Claude connect over MCP, the Model Context Protocol. Claude calls your API through plain conversation.
Kubb generates type-safe code from your OpenAPI spec, including the API client files, the Zod schemas, and an MCP server. Claude reads the MCP server and runs the matching API calls as you chat.
Installation#
Install Claude desktop and work through the user quickstart, then install Kubb with the MCP plugin.
Tip
The MCP plugin builds on the OpenAPI adapter, the TypeScript and Zod plugins, and a client plugin (axios or fetch) to generate every file it needs.
::: code-group
bun add -d kubb @kubb/plugin-ts @kubb/plugin-zod @kubb/plugin-axios @kubb/plugin-mcp
pnpm add -D kubb @kubb/plugin-ts @kubb/plugin-zod @kubb/plugin-axios @kubb/plugin-mcp
npm install --save-dev kubb @kubb/plugin-ts @kubb/plugin-zod @kubb/plugin-axios @kubb/plugin-mcp
yarn add -D kubb @kubb/plugin-ts @kubb/plugin-zod @kubb/plugin-axios @kubb/plugin-mcp
:::
Define kubb.config.ts#
Write a kubb.config.ts that sets up the MCP server.
pluginMcp depends on pluginTs and pluginZod, and each handler calls a registered client plugin. Add pluginAxios or pluginFetch, and pluginMcp detects it.
Important
Set the baseURL on the client plugin so the generated handlers know which host to call.
import { defineConfig } from 'kubb/config'
import { pluginTs } from '@kubb/plugin-ts'
import { pluginZod } from '@kubb/plugin-zod'
import { pluginAxios } from '@kubb/plugin-axios'
import { pluginMcp } from '@kubb/plugin-mcp'
export default defineConfig({
input: './petStore.yaml',
output: {
path: './src/gen',
},
plugins: [
pluginTs({ output: { path: 'types', mode: 'directory' } }),
pluginZod({ output: { path: 'zod', mode: 'directory' } }),
pluginAxios({
+ baseURL: 'https://petstore.swagger.io/v2',
}),
pluginMcp(),
],
})
Generate MCP files#
npx kubb generate
Inspect the generated files#
The src/mcp folder holds the files that build an MCP server and connect Claude to your API.
src/mcp/addPet.ts#
The addPetHandler function takes the pet body and calls the generated addPet client function. It returns the response as a JSON text message that MCP uses in conversations.
import type { AddPetOptions } from '../types/AddPet'
import type { RequestHandlerExtra } from '@modelcontextprotocol/sdk/shared/protocol'
import type { CallToolResult, ServerNotification, ServerRequest } from '@modelcontextprotocol/sdk/types'
import { addPet } from '../clients/addPet'
export async function addPetHandler(
{ body }: AddPetOptions,
request: RequestHandlerExtra<ServerRequest, ServerNotification>,
): Promise<Promise<CallToolResult>> {
const res = await addPet({ body })
return {
content: [
{
type: 'text',
text: JSON.stringify(res.data),
},
],
structuredContent: { data: res.data },
}
}
src/mcp/.mcp.json#
This config registers an MCP server named "Swagger PetStore - OpenAPI 3.0". The name comes from info.title in your OpenAPI file.
It runs the TypeScript server (server.ts) through tsx, so MCP handles tool calls over standard input and output.
{
"mcpServers": {
"Swagger PetStore - OpenAPI 3.0": {
"type": "stdio",
"command": "npx",
"args": ["tsx", "server.ts"]
}
}
}
src/mcp/server.ts#
This code starts an MCP server for the Swagger PetStore API in four steps:
- Import the MCP SDK classes, each operation handler, and the Zod input schemas.
- Create an MCP server named
"Swagger PetStore - OpenAPI 3.0". - Register the
addPettool. It validates the input againstaddPetBodySchemafrom the Zod plugin, then callsaddPetHandler. - Connect the server to a
stdiotransport so it talks over standard input and output.
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio'
import { addPetHandler } from './addPet'
import { addPetBodySchema, addPetStatus200Schema } from '../zod/addPetSchema'
export function getServer() {
const server = new McpServer({
name: 'Swagger PetStore - OpenAPI 3.0',
version: '1.0.11',
})
server.registerTool(
'addPet',
{
title: 'Add a new pet to the store',
description: 'Add a new pet to the store',
outputSchema: { data: addPetStatus200Schema },
inputSchema: { body: addPetBodySchema },
},
async ({ body }, request) => {
return addPetHandler({ body }, request)
},
)
return server
}
export const server = getServer()
export async function startServer() {
try {
const transport = new StdioServerTransport()
await server.connect(transport)
} catch (error) {
console.error('Failed to start server:', error)
process.exit(1)
}
}
startServer()
Start Claude with the MCP server#
Point Claude at your MCP server config (src/mcp/.mcp.json). Open Claude desktop and go to settings.
![]()
In the settings panel, open the developer section and click edit config. A window shows where the JSON file that lists your MCP servers lives.
Tip
Manually navigate to:
- Mac:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
![]()
Copy the content of src/mcp/.mcp.json so Claude picks up your MCP server.
Tip
With multiple MCP servers, append your entry instead of overwriting the file.
For example:
{
"mcpServers": {
"Swagger PetStore - OpenAPI 3.0": {
"type": "stdio",
"command": "npx",
"args": ["tsx", "mcp/src/gen/mcp/server.ts"]
},
"github": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"GITHUB_PERSONAL_ACCESS_TOKEN",
"mcp/github"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
}
}
}
}
Validate your MCP server#
Quit Claude and reopen the desktop app. Click the button below to check that your MCP server is connected.
![]()
The view below opens and shows your generated MCP server.
![]()
Use your MCP server#
The prompt create a random pet reaches your MCP server. The server maps it to the addPet tool, which calls addPetHandler and creates the pet.
![]()