@kubb/plugin-mcp 5.0.0-beta.15 → 5.0.0-beta.25

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/extension.yaml CHANGED
@@ -2,7 +2,7 @@ $schema: https://kubb.dev/schemas/extension.json
2
2
  kind: plugin
3
3
  id: plugin-mcp
4
4
  name: MCP
5
- description: Generate Model Context Protocol (MCP) servers from OpenAPI specifications for AI assistants to call your API.
5
+ description: Generate a Model Context Protocol (MCP) server from OpenAPI so AI assistants like Claude can call your API as tools.
6
6
  category: ai
7
7
  type: official
8
8
  npmPackage: '@kubb/plugin-mcp'
@@ -39,88 +39,310 @@ icon:
39
39
  intro: |
40
40
  # @kubb/plugin-mcp
41
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.
42
+ Generate a [Model Context Protocol](https://modelcontextprotocol.io/introduction) server straight from your OpenAPI spec. Every operation becomes a typed MCP tool that AI assistants (Claude Desktop, Claude Code, MCP-compatible clients) can call directly.
43
+
44
+ The plugin emits the tool definitions, the request handlers, and the Zod schemas they validate against. Plug the generated server into Claude with one config file.
43
45
 
44
46
  ```mermaid
45
47
  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
48
+ A[OpenAPI spec] --> B[Kubb<br/>code generation]
49
+ B --> C[MCP server<br/>tool registry]
50
+ C --> D[Claude / MCP client]
51
+ D -->|Tool call| C
52
+ C -->|HTTP request| E[Your API]
50
53
  ```
51
54
  notes:
52
55
  - type: tip
53
56
  body: |
54
- See [Setup Claude with Kubb](https://modelcontextprotocol.io/docs/tools/claude-desktop) for configuration instructions.
57
+ See [Connect Claude to a remote MCP server](https://modelcontextprotocol.io/docs/tools/claude-desktop) for connecting the generated server.
55
58
  options:
56
59
  - name: output
57
60
  type: Output
58
61
  required: false
59
62
  default: "{ path: 'mcp', barrel: { type: 'named' } }"
60
- description: Specify the export location for the files and define the behavior of the output.
63
+ description: Where the generated MCP tool handlers are written and how they are exported.
61
64
  properties:
62
65
  - name: path
63
66
  type: string
64
67
  required: true
65
- description: Output directory or file for the generated code, relative to the global `output.path`.
68
+ description: |
69
+ Folder (or single file) where the plugin writes its generated code. The path is resolved against the global `output.path` set on `defineConfig`.
70
+
71
+ Use a folder to keep each generator's output isolated (`'types'`, `'clients'`, `'hooks'`). Use a single file when you want everything in one place, for example `'api.ts'`.
66
72
  tip: |
67
- if `output.path` is a file, `group` cannot be used.
73
+ When `output.path` points to a single file, the `group` option cannot be used because every operation ends up in the same file.
74
+ examples:
75
+ - name: kubb.config.ts
76
+ files:
77
+ - lang: typescript
78
+ twoslash: false
79
+ code: |
80
+ import { defineConfig } from 'kubb'
81
+ import { pluginTs } from '@kubb/plugin-ts'
82
+
83
+ export default defineConfig({
84
+ input: { path: './petStore.yaml' },
85
+ output: { path: './src/gen' },
86
+ plugins: [
87
+ pluginTs({
88
+ output: { path: './types' },
89
+ }),
90
+ ],
91
+ })
92
+ - name: Resulting tree
93
+ files:
94
+ - lang: text
95
+ twoslash: false
96
+ code: |
97
+ src/
98
+ └── gen/
99
+ └── types/
100
+ ├── Pet.ts
101
+ └── Store.ts
68
102
  default: "'mcp'"
69
103
  - name: barrel
70
104
  type: "{ type: 'named' | 'all', nested?: boolean } | false"
71
105
  required: false
72
106
  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.'
107
+ description: |
108
+ Controls how the generated `index.ts` (barrel) file re-exports the plugin's output.
109
+
110
+ - `{ type: 'named' }` re-exports each symbol by name. Best for tree-shaking and explicit imports.
111
+ - `{ type: 'all' }` uses `export *`. Smaller barrel file, but exports everything.
112
+ - `{ nested: true }` creates a barrel in every subdirectory, so callers can import from any depth.
113
+ - `false` skips the barrel entirely. The plugin's files are also excluded from the root `index.ts`.
114
+ tip: |
115
+ Pick `'named'` when consumers care about which symbols they import (better tree-shaking, friendlier auto-import). Pick `'all'` when the file count is small and you want a one-line barrel.
74
116
  examples:
75
- - name: all
117
+ - name: "'named' (default)"
76
118
  files:
77
- - lang: typescript
119
+ - name: kubb.config.ts
120
+ lang: typescript
121
+ twoslash: false
78
122
  code: |
79
- export * from './gen/petService.ts'
123
+ import { defineConfig } from 'kubb'
124
+ import { pluginTs } from '@kubb/plugin-ts'
125
+
126
+ export default defineConfig({
127
+ input: { path: './petStore.yaml' },
128
+ output: { path: './src/gen' },
129
+ plugins: [
130
+ pluginTs({
131
+ output: { barrel: { type: 'named' } },
132
+ }),
133
+ ],
134
+ })
135
+ - name: src/gen/types/index.ts
136
+ lang: typescript
80
137
  twoslash: false
81
- - name: named
138
+ code: |
139
+ export { Pet, PetStatus } from './Pet'
140
+ export { Store } from './Store'
141
+ - name: "'all'"
82
142
  files:
83
- - lang: typescript
143
+ - name: kubb.config.ts
144
+ lang: typescript
145
+ twoslash: false
84
146
  code: |
85
- export { PetService } from './gen/petService.ts'
147
+ import { defineConfig } from 'kubb'
148
+ import { pluginTs } from '@kubb/plugin-ts'
149
+
150
+ export default defineConfig({
151
+ input: { path: './petStore.yaml' },
152
+ output: { path: './src/gen' },
153
+ plugins: [
154
+ pluginTs({
155
+ output: { barrel: { type: 'all' } },
156
+ }),
157
+ ],
158
+ })
159
+ - name: src/gen/types/index.ts
160
+ lang: typescript
86
161
  twoslash: false
162
+ code: |
163
+ export * from './Pet'
164
+ export * from './Store'
87
165
  - name: nested
88
166
  files:
89
167
  - name: kubb.config.ts
90
168
  lang: typescript
169
+ twoslash: false
91
170
  code: |
92
- output: {
93
- path: './gen',
94
- barrel: { type: 'named', nested: true },
95
- }
171
+ import { defineConfig } from 'kubb'
172
+ import { pluginTs } from '@kubb/plugin-ts'
173
+
174
+ export default defineConfig({
175
+ input: { path: './petStore.yaml' },
176
+ output: { path: './src/gen' },
177
+ plugins: [
178
+ pluginTs({
179
+ output: { barrel: { type: 'named', nested: true } },
180
+ }),
181
+ ],
182
+ })
183
+ - name: Generated tree
184
+ lang: text
96
185
  twoslash: false
186
+ code: |
187
+ src/gen/types/
188
+ ├── index.ts # re-exports ./petController and ./storeController
189
+ ├── petController/
190
+ │ ├── index.ts # re-exports Pet, Store, ...
191
+ │ └── Pet.ts
192
+ └── storeController/
193
+ ├── index.ts
194
+ └── Store.ts
97
195
  - name: 'false'
98
196
  files:
99
- - lang: typescript
100
- code: ''
197
+ - name: kubb.config.ts
198
+ lang: typescript
101
199
  twoslash: false
200
+ code: |
201
+ import { defineConfig } from 'kubb'
202
+ import { pluginTs } from '@kubb/plugin-ts'
203
+
204
+ export default defineConfig({
205
+ input: { path: './petStore.yaml' },
206
+ output: { path: './src/gen' },
207
+ plugins: [
208
+ pluginTs({
209
+ output: { barrel: false },
210
+ }),
211
+ ],
212
+ })
213
+ - name: Result
214
+ lang: text
215
+ twoslash: false
216
+ code: |
217
+ # No index.ts is generated for this plugin.
218
+ # Its files are also excluded from the root index.ts.
102
219
  - name: banner
103
220
  type: 'string | ((node: RootNode) => string)'
104
221
  required: false
105
- 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.
222
+ description: |
223
+ Text prepended to every generated file. Useful for license headers, lint disables, or `@ts-nocheck` directives.
224
+
225
+ Pass a string for a static banner. Pass a function to compute the banner from each file's `RootNode` (the AST root containing path, schema, and operation context).
226
+ examples:
227
+ - name: Static banner
228
+ files:
229
+ - name: kubb.config.ts
230
+ lang: typescript
231
+ twoslash: false
232
+ code: |
233
+ import { defineConfig } from 'kubb'
234
+ import { pluginTs } from '@kubb/plugin-ts'
235
+
236
+ export default defineConfig({
237
+ input: { path: './petStore.yaml' },
238
+ output: { path: './src/gen' },
239
+ plugins: [
240
+ pluginTs({
241
+ output: {
242
+ banner: '/* eslint-disable */\n// @ts-nocheck',
243
+ },
244
+ }),
245
+ ],
246
+ })
247
+ - name: Generated file
248
+ lang: typescript
249
+ twoslash: false
250
+ code: |
251
+ /* eslint-disable */
252
+ // @ts-nocheck
253
+ export type Pet = {
254
+ id: number
255
+ name: string
256
+ }
257
+ - name: Dynamic banner
258
+ files:
259
+ - name: kubb.config.ts
260
+ lang: typescript
261
+ twoslash: false
262
+ code: |
263
+ import { defineConfig } from 'kubb'
264
+ import { pluginTs } from '@kubb/plugin-ts'
265
+
266
+ export default defineConfig({
267
+ input: { path: './petStore.yaml' },
268
+ output: { path: './src/gen' },
269
+ plugins: [
270
+ pluginTs({
271
+ output: {
272
+ banner: (node) => `// Source: ${node.path}\n// Generated at ${new Date().toISOString()}`,
273
+ },
274
+ }),
275
+ ],
276
+ })
106
277
  - name: footer
107
278
  type: 'string | ((node: RootNode) => string)'
108
279
  required: false
109
- 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.
280
+ description: |
281
+ Text appended at the end of every generated file. The mirror of `banner` — use it for closing comments, re-enabling lint rules, or marker lines.
282
+
283
+ Pass a string for a static footer, or a function that receives the file's `RootNode` and returns the footer text.
284
+ examples:
285
+ - name: Re-enable lint after a banner disable
286
+ files:
287
+ - name: kubb.config.ts
288
+ lang: typescript
289
+ twoslash: false
290
+ code: |
291
+ import { defineConfig } from 'kubb'
292
+ import { pluginTs } from '@kubb/plugin-ts'
293
+
294
+ export default defineConfig({
295
+ input: { path: './petStore.yaml' },
296
+ output: { path: './src/gen' },
297
+ plugins: [
298
+ pluginTs({
299
+ output: {
300
+ banner: '/* eslint-disable */',
301
+ footer: '/* eslint-enable */',
302
+ },
303
+ }),
304
+ ],
305
+ })
110
306
  - name: override
111
307
  type: boolean
112
308
  required: false
113
309
  default: 'false'
114
- description: Whether Kubb overrides existing external files that can be generated if they already exist.
310
+ description: |
311
+ Allows the plugin to overwrite hand-written files that share a name with a generated file.
312
+
313
+ - `false` (default): Kubb skips a file if it already exists and is not marked as generated. This protects manual edits.
314
+ - `true`: Kubb overwrites any file at the target path, including hand-written ones.
315
+ warning: |
316
+ Enable this only when you are sure the target folder contains nothing you need to keep. Local edits are lost on the next generation.
317
+ examples:
318
+ - name: kubb.config.ts
319
+ files:
320
+ - lang: typescript
321
+ twoslash: false
322
+ code: |
323
+ import { defineConfig } from 'kubb'
324
+ import { pluginTs } from '@kubb/plugin-ts'
325
+
326
+ export default defineConfig({
327
+ input: { path: './petStore.yaml' },
328
+ output: { path: './src/gen' },
329
+ plugins: [
330
+ pluginTs({
331
+ output: { override: true },
332
+ }),
333
+ ],
334
+ })
115
335
  - name: resolver
116
336
  type: Partial<ResolverMcp> & ThisType<ResolverMcp>
117
337
  required: false
118
338
  description: |
119
- 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.
339
+ Overrides how the plugin builds names and paths for generated files and symbols. Use this to add prefixes, suffixes, or to swap the casing strategy without forking the plugin.
340
+
341
+ Only override the methods you want to change. Anything you omit falls back to the plugin's default resolver. A method that returns `null` or `undefined` also falls back.
120
342
 
121
- `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.
343
+ Inside each method, `this` is bound to the full resolver, so you can call `this.default(name, 'function')` to delegate to the built-in implementation.
122
344
  body: |
123
- Each plugin ships a built-in resolver:
345
+ Each plugin ships with a default resolver:
124
346
 
125
347
  | Plugin | Default resolver |
126
348
  | --- | --- |
@@ -128,157 +350,183 @@ options:
128
350
  | `@kubb/plugin-zod` | `resolverZod` |
129
351
  | `@kubb/plugin-cypress` | `resolverCypress` |
130
352
  | `@kubb/plugin-mcp` | `resolverMcp` |
353
+ | `@kubb/plugin-client` | `resolverClient` |
131
354
  codeBlock:
132
355
  lang: typescript
133
- title: Custom resolver (plugin-mcp example)
356
+ title: Prefix every tool name with "Mcp"
134
357
  code: |
358
+ import { defineConfig } from 'kubb'
135
359
  import { pluginMcp } from '@kubb/plugin-mcp'
136
360
 
137
- pluginMcp({
138
- resolver: {
139
- resolveName(name) {
140
- return `Mcp${this.default(name, 'function')}`
141
- },
142
- },
361
+ export default defineConfig({
362
+ input: { path: './petStore.yaml' },
363
+ output: { path: './src/gen' },
364
+ plugins: [
365
+ pluginMcp({
366
+ resolver: {
367
+ resolveName(name) {
368
+ return `Mcp${this.default(name, 'function')}`
369
+ },
370
+ },
371
+ }),
372
+ ],
143
373
  })
144
374
  tip: |
145
- Use `resolver` for fine-grained control over naming conventions.
375
+ Use `resolver` for naming and file-location tweaks. For changing the AST nodes themselves (e.g. stripping descriptions), use `transformer` instead.
146
376
  - name: group
147
377
  type: Group
148
378
  required: false
149
379
  description: |
150
- Grouping combines files in a folder based on a specific `type`.
380
+ Splits generated files into subfolders based on the operation's tag, so each tag in your OpenAPI spec gets its own directory.
381
+
382
+ Without `group`, every file lands in the plugin's `output.path` folder. With `group`, files are bucketed under `{output.path}/{groupName}/`, where `groupName` is derived from the operation's first tag.
383
+ tip: |
384
+ Use `group` to mirror your API's domain structure (pet, store, user) in the generated code. Combine it with `output.barrel: { type: 'named', nested: true }` to get per-tag barrel files.
151
385
  examples:
152
386
  - name: kubb.config.ts
153
387
  files:
154
388
  - lang: typescript
155
- code: |
156
- group: {
157
- type: 'tag',
158
- name({ group }) {
159
- return `${group}Controller`
160
- }
161
- }
162
389
  twoslash: false
390
+ code: |
391
+ import { defineConfig } from 'kubb'
392
+ import { pluginTs } from '@kubb/plugin-ts'
393
+
394
+ export default defineConfig({
395
+ input: { path: './petStore.yaml' },
396
+ output: { path: './src/gen' },
397
+ plugins: [
398
+ pluginTs({
399
+ group: {
400
+ type: 'tag',
401
+ name: ({ group }) => `${group}Controller`,
402
+ },
403
+ }),
404
+ ],
405
+ })
163
406
  body: |
164
407
  With the configuration above, the generator emits:
165
408
 
166
409
  ```text
167
- .
168
- ├── src/
169
- └── petController/
170
- │ ├── addPet.ts
171
- │ │ └── getPet.ts
172
- │ └── storeController/
173
- │ ├── createStore.ts
174
- │ └── getStoreById.ts
175
- ├── petStore.yaml
176
- ├── kubb.config.ts
177
- └── package.json
410
+ src/gen/
411
+ ├── petController/
412
+ ├── AddPet.ts
413
+ └── GetPet.ts
414
+ └── storeController/
415
+ ├── CreateStore.ts
416
+ └── GetStoreById.ts
178
417
  ```
179
418
  properties:
180
419
  - name: type
181
420
  type: "'tag'"
182
421
  required: true
183
- description: Specify the property to group files by. Required when `group` is defined.
422
+ description: |
423
+ Property used to assign each operation to a group. Required whenever `group` is set.
424
+
425
+ Today only `'tag'` is supported: Kubb reads the first tag on the operation (`operation.getTags().at(0)?.name`) and uses it as the group key. Operations without a tag are placed in a default group.
184
426
  note: |
185
- `Required: true*` means this is required only when the `group` option is used. The `group` option itself is optional.
186
- body: |
187
- - `'tag'`: Uses the first tag from `operation.getTags().at(0)?.name`
427
+ `Required: true*` is conditional only required when the parent `group` option is used. `group` itself stays optional.
188
428
  - name: name
189
429
  type: '(context: GroupContext) => string'
190
430
  required: false
191
431
  default: (ctx) => `${ctx.group}Requests`
192
- description: Return the name of a group based on the group name. This is used for file and identifier generation.
432
+ description: Function that builds the folder/identifier name from a group key (the operation's first tag).
193
433
  - name: paramsCasing
194
434
  type: "'camelcase'"
195
435
  required: false
196
- description: Transform parameter names to camelCase in generated MCP handlers.
436
+ description: |
437
+ Renames parameter properties in the generated MCP handlers. The HTTP layer still uses the original spec names — Kubb adds the mapping for you.
197
438
  important: |
198
- 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.
199
- body: |
200
- - `'camelcase'` transforms parameter names to camelCase.
439
+ Set the same `paramsCasing` here as on `@kubb/plugin-ts` so the handlers' parameter types line up with the generated request types.
201
440
  examples:
202
- - name: With paramsCasing camelcase
441
+ - name: "With `paramsCasing: 'camelcase'`"
203
442
  files:
204
443
  - lang: typescript
444
+ twoslash: false
205
445
  code: |
206
- // Handler uses camelCase parameters
446
+ // Handler signature uses camelCase
207
447
  export async function findPetsByStatusHandler({
208
- stepId // ✓ camelCase
448
+ stepId,
209
449
  }: {
210
450
  stepId: FindPetsByStatusPathParams['stepId']
211
- }): Promise<Promise<CallToolResult>> {
212
- // Automatically maps back to original name
451
+ }): Promise<CallToolResult> {
213
452
  const step_id = stepId
214
453
 
215
454
  const res = await fetch({
216
455
  method: 'GET',
217
- url: `/pet/findByStatus/${step_id}`, // Uses original API name
218
- ...
456
+ url: `/pet/findByStatus/${step_id}`,
219
457
  })
220
- ...
458
+ // ...
221
459
  }
222
- twoslash: false
223
- - name: Without paramsCasing
460
+ - name: Without `paramsCasing`
224
461
  files:
225
462
  - lang: typescript
463
+ twoslash: false
226
464
  code: |
227
- // Handler uses original API naming
228
465
  export async function findPetsByStatusHandler({
229
- step_id // Original naming
466
+ step_id,
230
467
  }: {
231
468
  step_id: FindPetsByStatusPathParams['step_id']
232
- }): Promise<Promise<CallToolResult>> {
469
+ }): Promise<CallToolResult> {
233
470
  const res = await fetch({
234
471
  method: 'GET',
235
472
  url: `/pet/findByStatus/${step_id}`,
236
- ...
237
473
  })
238
- ...
474
+ // ...
239
475
  }
240
- twoslash: false
241
476
  - name: client
242
477
  type: ClientImportPath & { clientType?, dataReturnType?, baseURL?, bundle?, paramsCasing? }
243
478
  required: false
244
- description: Client configuration for HTTP request generation, including client type, data return type, base URL, and bundling options.
479
+ description: |
480
+ HTTP client used by each MCP handler to call the underlying API. Mirrors a subset of `pluginClient` options.
245
481
  properties:
246
482
  - name: importPath
247
483
  type: string
248
484
  required: false
249
- description: Path to the client used for API calls. Supports both relative and absolute paths.
485
+ description: |
486
+ Path or module specifier of a custom client module. Generated code imports its HTTP runtime from here instead of `@kubb/plugin-client/clients/{client}`.
487
+
488
+ Use this when you need to inject auth headers, add interceptors, change the base URL at runtime, or wrap a different HTTP library (ky, ofetch, ...). Both relative paths (`./src/client.ts`) and bare specifiers (`@my-org/api-client`) work.
250
489
  details:
251
490
  - title: When to use `importPath`
252
491
  body: |
253
- Use `importPath` when you want to:
492
+ Reach for a custom client when you need to:
254
493
 
255
- - **Customize the HTTP client**: Provide your own client implementation with custom configurations (e.g., baseURL, headers, interceptors)
256
- - **Add authentication**: Include authentication tokens or other security mechanisms in your client
257
- - **Override default behavior**: Replace the default Kubb client with your own implementation
494
+ - Add an auth token to every request.
495
+ - Plug in interceptors, retries, or logging.
496
+ - Configure `baseURL` and headers from environment variables.
497
+ - Wrap a library other than `axios`/`fetch`.
258
498
  - title: Default behavior
259
499
  body: |
260
- When `importPath` is not specified:
500
+ Without `importPath`:
261
501
 
262
- - If `bundle: false` (default): Uses `@kubb/plugin-client/clients/${client}` where client is either `axios` or `fetch`.
263
- - If `bundle: true`: Bundles the client into `.kubb/fetch.ts`.
264
- - title: Import structure
265
- body: 'Generated code imports the client as a default import and the runtime types as named type imports:'
502
+ - `bundle: false` (default) generated code imports from `@kubb/plugin-client/clients/{axios|fetch}`.
503
+ - `bundle: true` Kubb writes `.kubb/fetch.ts` (or `.kubb/axios.ts`) and generated code imports from there.
504
+ - title: Required exports
505
+ body: |
506
+ The module pointed to by `importPath` must satisfy the same shape as the built-in client. At minimum:
507
+
508
+ - A default export of the `client` function.
509
+ - A `RequestConfig` type.
510
+ - A `ResponseErrorConfig` type.
511
+
512
+ When used together with a query plugin (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`), it must also export a `Client` type alias.
513
+ - title: How generated files import it
514
+ body: |
515
+ Generated code imports the client as a default import and the runtime types as named type imports:
266
516
  codeBlock:
267
517
  lang: typescript
268
- code: |-
269
- /**
270
- * Generated by Kubb (https://kubb.dev/).
271
- * Do not edit manually.
272
- */
518
+ code: |
273
519
  import client from '${client.importPath}'
274
520
  import type { RequestConfig, ResponseErrorConfig } from '${client.importPath}'
275
- // ... rest of generated file
521
+ // ... rest of the generated file
276
522
  important: |
277
- 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 typesif any is missing, TypeScript will report an unresolvable import error.
523
+ When used with query plugins (`@kubb/plugin-react-query`, `@kubb/plugin-vue-query`), generated hooks also import a `Client` type alias. Your module **must** export `Client`, `RequestConfig`, and `ResponseErrorConfig` — TypeScript will fail the import otherwise.
278
524
  codeBlock:
279
525
  lang: typescript
280
- title: client.ts
526
+ title: src/client.ts
281
527
  code: |
528
+ import axios from 'axios'
529
+
282
530
  export type RequestConfig<TData = unknown> = {
283
531
  url?: string
284
532
  method: 'GET' | 'PUT' | 'PATCH' | 'POST' | 'DELETE'
@@ -297,153 +545,359 @@ options:
297
545
 
298
546
  export type ResponseErrorConfig<TError = unknown> = TError
299
547
 
300
- // The Client type alias is required when using query plugins
548
+ // Required when used with @kubb/plugin-react-query or @kubb/plugin-vue-query
301
549
  export type Client = <TData, _TError = unknown, TVariables = unknown>(
302
- config: RequestConfig<TVariables>
550
+ config: RequestConfig<TVariables>,
303
551
  ) => Promise<ResponseConfig<TData>>
304
552
 
305
- export const client: Client = async (config) => { /* ... */ }
553
+ const client: Client = async (config) => {
554
+ const response = await axios.request<TData>({
555
+ ...config,
556
+ headers: {
557
+ Authorization: `Bearer ${process.env.API_TOKEN}`,
558
+ ...config.headers,
559
+ },
560
+ })
561
+
562
+ return response
563
+ }
564
+
306
565
  export default client
307
566
  examples:
308
- - name: kubb.config.ts
567
+ - name: Wire up a custom client
309
568
  files:
310
- - lang: typescript
569
+ - name: kubb.config.ts
570
+ lang: typescript
571
+ twoslash: false
311
572
  code: |
312
573
  import { defineConfig } from 'kubb'
313
574
  import { pluginClient } from '@kubb/plugin-client'
314
575
 
315
576
  export default defineConfig({
316
- // ...
577
+ input: { path: './petStore.yaml' },
578
+ output: { path: './src/gen' },
317
579
  plugins: [
318
580
  pluginClient({
319
- importPath: './src/client.ts', // Path to your custom client
581
+ importPath: './src/client.ts',
320
582
  }),
321
583
  ],
322
584
  })
323
- twoslash: false
324
585
  tip: |
325
- Learn more about defining a custom client [here](https://kubb.dev/plugins/plugin-client#importpath).
586
+ See the [custom client guide](https://kubb.dev/plugins/plugin-client#importpath) for a worked example.
326
587
  - name: dataReturnType
327
588
  type: "'data' | 'full'"
328
589
  required: false
329
590
  default: "'data'"
330
591
  description: |
331
- Return type used when calling the client.
592
+ Shape of the value returned from each generated client function.
332
593
 
333
- - `'data'` returns `ResponseConfig['data']`.
334
- - `'full'` returns the full `ResponseConfig`.
594
+ - `'data'` returns only the response body (`response.data`). Concise and matches what most apps need.
595
+ - `'full'` returns the full response config — body, status code, headers, and the original request. Use this when callers need to inspect headers or status.
335
596
  examples:
336
- - name: data
597
+ - name: "'data' (default)"
337
598
  files:
338
- - lang: typescript
599
+ - name: getPetById.ts
600
+ lang: typescript
601
+ twoslash: false
339
602
  code: |
340
603
  export async function getPetById<TData>(
341
604
  petId: GetPetByIdPathParams,
342
605
  ): Promise<ResponseConfig<TData>['data']> {
343
- ...
606
+ // ...
344
607
  }
608
+ - name: usage.ts
609
+ lang: typescript
345
610
  twoslash: false
346
- - name: full
611
+ code: |
612
+ const pet = await getPetById(1)
613
+ // ^? Pet
614
+ - name: "'full'"
347
615
  files:
348
- - lang: typescript
616
+ - name: getPetById.ts
617
+ lang: typescript
618
+ twoslash: false
349
619
  code: |
350
620
  export async function getPetById<TData>(
351
621
  petId: GetPetByIdPathParams,
352
622
  ): Promise<ResponseConfig<TData>> {
353
- ...
623
+ // ...
354
624
  }
625
+ - name: usage.ts
626
+ lang: typescript
355
627
  twoslash: false
628
+ code: |
629
+ const response = await getPetById(1)
630
+ // ^? ResponseConfig<Pet>
631
+ console.log(response.status, response.headers)
632
+ const pet = response.data
356
633
  - name: baseURL
357
634
  type: string
358
635
  required: false
359
- 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).
636
+ description: |
637
+ Base URL prepended to every request URL in the generated client. When omitted, the URL comes from the OpenAPI spec's `servers[0].url` (or whichever index the adapter is configured to read).
638
+
639
+ Set this when the generated client should point at a different environment (staging, production) than the one written in the spec.
640
+ examples:
641
+ - name: Override the spec's server URL
642
+ files:
643
+ - lang: typescript
644
+ twoslash: false
645
+ code: |
646
+ import { defineConfig } from 'kubb'
647
+ import { pluginClient } from '@kubb/plugin-client'
648
+
649
+ export default defineConfig({
650
+ input: { path: './petStore.yaml' },
651
+ output: { path: './src/gen' },
652
+ plugins: [
653
+ pluginClient({
654
+ baseURL: 'https://petstore.swagger.io/v2',
655
+ }),
656
+ ],
657
+ })
360
658
  - name: include
361
659
  type: Array<Include>
362
660
  required: false
363
- description: Array containing include parameters to include tags, operations, methods, paths, or content types.
661
+ description: |
662
+ Restricts generation to operations that match at least one entry in the list. Anything not matched is skipped.
663
+
664
+ Each entry filters by one of:
665
+
666
+ - `tag` — the operation's first tag in the OpenAPI spec.
667
+ - `operationId` — the operation's `operationId`.
668
+ - `path` — the URL pattern (`'/pet/{petId}'`).
669
+ - `method` — HTTP method (`'get'`, `'post'`, ...).
670
+ - `contentType` — the media type of the request body.
671
+
672
+ `pattern` accepts either a string (exact match) or a `RegExp` for fuzzy matches.
364
673
  codeBlock:
365
674
  lang: typescript
366
- title: Include
675
+ title: Type definition
367
676
  code: |
368
677
  export type Include = {
369
678
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
370
679
  pattern: string | RegExp
371
680
  }
681
+ examples:
682
+ - name: Only the pet tag
683
+ files:
684
+ - name: kubb.config.ts
685
+ lang: typescript
686
+ twoslash: false
687
+ code: |
688
+ import { defineConfig } from 'kubb'
689
+ import { pluginTs } from '@kubb/plugin-ts'
690
+
691
+ export default defineConfig({
692
+ input: { path: './petStore.yaml' },
693
+ output: { path: './src/gen' },
694
+ plugins: [
695
+ pluginTs({
696
+ include: [
697
+ { type: 'tag', pattern: 'pet' },
698
+ ],
699
+ }),
700
+ ],
701
+ })
702
+ - name: Only GET operations under /pet
703
+ files:
704
+ - name: kubb.config.ts
705
+ lang: typescript
706
+ twoslash: false
707
+ code: |
708
+ import { defineConfig } from 'kubb'
709
+ import { pluginTs } from '@kubb/plugin-ts'
710
+
711
+ export default defineConfig({
712
+ input: { path: './petStore.yaml' },
713
+ output: { path: './src/gen' },
714
+ plugins: [
715
+ pluginTs({
716
+ include: [
717
+ { type: 'method', pattern: 'get' },
718
+ { type: 'path', pattern: /^\/pet/ },
719
+ ],
720
+ }),
721
+ ],
722
+ })
372
723
  - name: exclude
373
724
  type: Array<Exclude>
374
725
  required: false
375
- description: Array containing exclude parameters to exclude or skip tags, operations, methods, paths, or content types.
726
+ description: |
727
+ Skips any operation that matches at least one entry in the list. The opposite of `include`.
728
+
729
+ Each entry filters by one of:
730
+
731
+ - `tag` — the operation's first tag.
732
+ - `operationId` — the operation's `operationId`.
733
+ - `path` — the URL pattern (`'/pet/{petId}'`).
734
+ - `method` — HTTP method (`'get'`, `'post'`, ...).
735
+ - `contentType` — the media type of the request body.
736
+
737
+ `pattern` accepts a plain string or a `RegExp`. When both `include` and `exclude` are set, `exclude` wins.
376
738
  codeBlock:
377
739
  lang: typescript
378
- title: Exclude
740
+ title: Type definition
379
741
  code: |
380
742
  export type Exclude = {
381
743
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
382
744
  pattern: string | RegExp
383
745
  }
746
+ examples:
747
+ - name: Skip everything under the store tag
748
+ files:
749
+ - name: kubb.config.ts
750
+ lang: typescript
751
+ twoslash: false
752
+ code: |
753
+ import { defineConfig } from 'kubb'
754
+ import { pluginTs } from '@kubb/plugin-ts'
755
+
756
+ export default defineConfig({
757
+ input: { path: './petStore.yaml' },
758
+ output: { path: './src/gen' },
759
+ plugins: [
760
+ pluginTs({
761
+ exclude: [
762
+ { type: 'tag', pattern: 'store' },
763
+ ],
764
+ }),
765
+ ],
766
+ })
767
+ - name: Skip a specific operation and all delete methods
768
+ files:
769
+ - name: kubb.config.ts
770
+ lang: typescript
771
+ twoslash: false
772
+ code: |
773
+ import { defineConfig } from 'kubb'
774
+ import { pluginTs } from '@kubb/plugin-ts'
775
+
776
+ export default defineConfig({
777
+ input: { path: './petStore.yaml' },
778
+ output: { path: './src/gen' },
779
+ plugins: [
780
+ pluginTs({
781
+ exclude: [
782
+ { type: 'operationId', pattern: 'deletePet' },
783
+ { type: 'method', pattern: 'delete' },
784
+ ],
785
+ }),
786
+ ],
787
+ })
384
788
  - name: override
385
789
  type: Array<Override>
386
790
  required: false
387
- description: Array containing override parameters to override `options` based on tags, operations, methods, paths, or content types.
791
+ description: |
792
+ Applies a different set of plugin options to operations that match a pattern. Use this when most of your API should follow the global config, but a handful of endpoints need different treatment.
793
+
794
+ Each entry has the same `type` and `pattern` shape as `include`/`exclude`, plus an `options` object that overrides the plugin's options for matched operations.
795
+
796
+ Entries are evaluated top to bottom. The first matching entry's `options` is merged onto the plugin defaults; later entries do not stack.
388
797
  codeBlock:
389
798
  lang: typescript
390
- title: Override
799
+ title: Type definition
391
800
  code: |
392
801
  export type Override = {
393
802
  type: 'tag' | 'operationId' | 'path' | 'method' | 'contentType'
394
803
  pattern: string | RegExp
395
804
  options: PluginOptions
396
805
  }
806
+ examples:
807
+ - name: Use a different enum style for the user tag
808
+ files:
809
+ - name: kubb.config.ts
810
+ lang: typescript
811
+ twoslash: false
812
+ code: |
813
+ import { defineConfig } from 'kubb'
814
+ import { pluginTs } from '@kubb/plugin-ts'
815
+
816
+ export default defineConfig({
817
+ input: { path: './petStore.yaml' },
818
+ output: { path: './src/gen' },
819
+ plugins: [
820
+ pluginTs({
821
+ enumType: 'asConst',
822
+ override: [
823
+ {
824
+ type: 'tag',
825
+ pattern: 'user',
826
+ options: { enumType: 'literal' },
827
+ },
828
+ ],
829
+ }),
830
+ ],
831
+ })
397
832
  - name: generators
398
833
  type: Array<Generator<PluginMcp>>
399
834
  required: false
400
835
  experimental: true
401
836
  description: |
402
- Define additional generators next to the built-in generators.
837
+ Adds custom generators that run alongside the plugin's built-in generators. Each generator can emit additional files or post-process existing ones using the plugin's AST and options.
403
838
 
404
- See [Generators](https://kubb.dev/docs/5.x/guides/creating-plugins) for more information on how to use generators.
839
+ Use this when you need output the plugin does not produce out of the box (a custom client wrapper, an extra index, a metadata file). For end-to-end guidance, see [Creating plugins](https://kubb.dev/docs/5.x/guides/creating-plugins).
840
+ warning: |
841
+ Generators are an experimental, low-level API. The signature may change between minor releases.
405
842
  - name: transformer
406
843
  type: Visitor
407
844
  required: false
408
845
  description: |
409
- 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.
846
+ Modifies AST nodes before they are printed to source code. Use this when you need to rewrite operation IDs, drop descriptions, or change schema metadata without forking the generator.
410
847
 
411
- Visitor methods receive the node and a context object. Return a modified node to replace it, or return `undefined`/`void` to leave it unchanged.
848
+ Each visitor method (e.g. `schema`, `operation`) receives the node and a context object. Return a new node to replace it, or return `undefined` to leave it untouched. Methods you omit keep the plugin's default behavior.
412
849
  examples:
413
850
  - name: Strip descriptions before printing
414
851
  files:
415
- - lang: typescript
852
+ - name: kubb.config.ts
853
+ lang: typescript
854
+ twoslash: false
416
855
  code: |
856
+ import { defineConfig } from 'kubb'
417
857
  import { pluginTs } from '@kubb/plugin-ts'
418
858
 
419
- pluginTs({
420
- transformer: {
421
- schema(node) {
422
- return { ...node, description: undefined }
423
- },
424
- },
859
+ export default defineConfig({
860
+ input: { path: './petStore.yaml' },
861
+ output: { path: './src/gen' },
862
+ plugins: [
863
+ pluginTs({
864
+ transformer: {
865
+ schema(node) {
866
+ return { ...node, description: undefined }
867
+ },
868
+ },
869
+ }),
870
+ ],
425
871
  })
426
- twoslash: false
427
872
  - name: Prefix every operationId
428
873
  files:
429
- - lang: typescript
874
+ - name: kubb.config.ts
875
+ lang: typescript
876
+ twoslash: false
430
877
  code: |
878
+ import { defineConfig } from 'kubb'
431
879
  import { pluginTs } from '@kubb/plugin-ts'
432
880
 
433
- pluginTs({
434
- transformer: {
435
- operation(node) {
436
- return { ...node, operationId: `api_${node.operationId}` }
437
- },
438
- },
881
+ export default defineConfig({
882
+ input: { path: './petStore.yaml' },
883
+ output: { path: './src/gen' },
884
+ plugins: [
885
+ pluginTs({
886
+ transformer: {
887
+ operation(node) {
888
+ return { ...node, operationId: `api_${node.operationId}` }
889
+ },
890
+ },
891
+ }),
892
+ ],
439
893
  })
440
- twoslash: false
441
894
  tip: |
442
- Use `transformer` to rewrite node properties before printing. For output naming customization, use `resolver` instead.
895
+ Use `transformer` to rewrite node properties before printing. For changing the names of generated symbols and files, use `resolver` instead.
443
896
  examples:
444
897
  - name: kubb.config.ts
445
898
  files:
446
899
  - lang: typescript
900
+ twoslash: false
447
901
  code: |
448
902
  import { defineConfig } from 'kubb'
449
903
  import { pluginTs } from '@kubb/plugin-ts'
@@ -470,4 +924,3 @@ examples:
470
924
  }),
471
925
  ],
472
926
  })
473
- twoslash: false