@kubb/plugin-mcp 5.0.0-beta.42 → 5.0.0-beta.64

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/src/plugin.ts DELETED
@@ -1,142 +0,0 @@
1
- import path from 'node:path'
2
- import { createGroupConfig } from '@internals/shared'
3
-
4
- import { ast, definePlugin } from '@kubb/core'
5
- import { pluginClientName } from '@kubb/plugin-client'
6
- import { source as axiosClientSource } from '@kubb/plugin-client/templates/clients/axios.source'
7
- import { source as fetchClientSource } from '@kubb/plugin-client/templates/clients/fetch.source'
8
- import { source as configSource } from '@kubb/plugin-client/templates/config.source'
9
- import { pluginTsName } from '@kubb/plugin-ts'
10
- import { pluginZodName } from '@kubb/plugin-zod'
11
- import { mcpGenerator } from './generators/mcpGenerator.tsx'
12
- import { serverGenerator } from './generators/serverGenerator.tsx'
13
- import { resolverMcp } from './resolvers/resolverMcp.ts'
14
- import type { PluginMcp } from './types.ts'
15
-
16
- /**
17
- * Canonical plugin name for `@kubb/plugin-mcp`. Used for driver lookups and
18
- * cross-plugin dependency references.
19
- */
20
- export const pluginMcpName = 'plugin-mcp' satisfies PluginMcp['name']
21
-
22
- /**
23
- * Generates a Model Context Protocol (MCP) server from an OpenAPI spec. Every
24
- * operation becomes a typed MCP tool that AI assistants (Claude Desktop, Claude
25
- * Code, MCP-compatible clients) can call directly.
26
- *
27
- * @example
28
- * ```ts
29
- * import { defineConfig } from 'kubb'
30
- * import { pluginTs } from '@kubb/plugin-ts'
31
- * import { pluginClient } from '@kubb/plugin-client'
32
- * import { pluginZod } from '@kubb/plugin-zod'
33
- * import { pluginMcp } from '@kubb/plugin-mcp'
34
- *
35
- * export default defineConfig({
36
- * input: { path: './petStore.yaml' },
37
- * output: { path: './src/gen' },
38
- * plugins: [
39
- * pluginTs(),
40
- * pluginClient(),
41
- * pluginZod(),
42
- * pluginMcp({
43
- * output: { path: './mcp' },
44
- * client: { baseURL: 'https://petstore.swagger.io/v2' },
45
- * }),
46
- * ],
47
- * })
48
- * ```
49
- */
50
- export const pluginMcp = definePlugin<PluginMcp>((options) => {
51
- const {
52
- output = { path: 'mcp', barrelType: 'named' },
53
- group,
54
- exclude = [],
55
- include,
56
- override = [],
57
- paramsCasing,
58
- client,
59
- resolver: userResolver,
60
- transformer: userTransformer,
61
- generators: userGenerators = [],
62
- } = options
63
-
64
- const clientName = client?.client ?? 'axios'
65
- const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : undefined)
66
-
67
- const groupConfig = createGroupConfig(group, { suffix: 'Requests' })
68
-
69
- return {
70
- name: pluginMcpName,
71
- options,
72
- dependencies: [pluginTsName, pluginZodName],
73
- hooks: {
74
- 'kubb:plugin:setup'(ctx) {
75
- const resolver = userResolver ? { ...resolverMcp, ...userResolver } : resolverMcp
76
-
77
- ctx.setOptions({
78
- output,
79
- exclude,
80
- include,
81
- override,
82
- group: groupConfig,
83
- paramsCasing,
84
- client: {
85
- client: clientName,
86
- clientType: client?.clientType ?? 'function',
87
- importPath: clientImportPath,
88
- dataReturnType: client?.dataReturnType ?? 'data',
89
- bundle: client?.bundle,
90
- baseURL: client?.baseURL,
91
- paramsCasing: client?.paramsCasing,
92
- },
93
- resolver,
94
- })
95
- ctx.setResolver(resolver)
96
- if (userTransformer) {
97
- ctx.setTransformer(userTransformer)
98
- }
99
- ctx.addGenerator(mcpGenerator)
100
- ctx.addGenerator(serverGenerator)
101
- for (const gen of userGenerators) {
102
- ctx.addGenerator(gen)
103
- }
104
-
105
- const root = path.resolve(ctx.config.root, ctx.config.output.path)
106
- const hasClientPlugin = ctx.config.plugins?.some((p) => p.name === pluginClientName)
107
-
108
- if (client?.bundle && !hasClientPlugin && !clientImportPath) {
109
- ctx.injectFile({
110
- baseName: 'client.ts',
111
- path: path.resolve(root, '.kubb/client.ts'),
112
- sources: [
113
- ast.createSource({
114
- name: 'client',
115
- nodes: [ast.createText(clientName === 'fetch' ? fetchClientSource : axiosClientSource)],
116
- isExportable: true,
117
- isIndexable: true,
118
- }),
119
- ],
120
- })
121
- }
122
-
123
- if (!hasClientPlugin) {
124
- ctx.injectFile({
125
- baseName: 'config.ts',
126
- path: path.resolve(root, '.kubb/config.ts'),
127
- sources: [
128
- ast.createSource({
129
- name: 'config',
130
- nodes: [ast.createText(configSource)],
131
- isExportable: false,
132
- isIndexable: false,
133
- }),
134
- ],
135
- })
136
- }
137
- },
138
- },
139
- }
140
- })
141
-
142
- export default pluginMcp
@@ -1,35 +0,0 @@
1
- import { camelCase } from '@internals/utils'
2
- import { defineResolver } from '@kubb/core'
3
- import type { PluginMcp } from '../types.ts'
4
-
5
- /**
6
- * Default resolver used by `@kubb/plugin-mcp`. Decides the names and file
7
- * paths for every generated MCP tool handler. Function names get a `Handler`
8
- * suffix so an operation `addPet` becomes `addPetHandler`.
9
- *
10
- * @example Resolve a handler name
11
- * ```ts
12
- * import { resolverMcp } from '@kubb/plugin-mcp'
13
- *
14
- * resolverMcp.default('addPet', 'function') // 'addPetHandler'
15
- * ```
16
- */
17
- export const resolverMcp = defineResolver<PluginMcp>(() => ({
18
- name: 'default',
19
- pluginName: 'plugin-mcp',
20
- default(name, type) {
21
- if (type === 'file') {
22
- return camelCase(name, { isFile: true })
23
- }
24
- return camelCase(name, { suffix: 'handler' })
25
- },
26
- resolveName(name) {
27
- return this.default(name, 'function')
28
- },
29
- resolvePathName(name, type) {
30
- return this.default(name, type)
31
- },
32
- resolveHandlerName(node) {
33
- return this.resolveName(node.operationId)
34
- },
35
- }))
package/src/types.ts DELETED
@@ -1,94 +0,0 @@
1
- import type { ast, Exclude, Generator, Group, Include, Output, Override, PluginFactoryOptions, Resolver } from '@kubb/core'
2
- import type { ClientImportPath, PluginClient } from '@kubb/plugin-client'
3
-
4
- /**
5
- * Resolver for MCP that provides naming methods for handler functions.
6
- */
7
- export type ResolverMcp = Resolver & {
8
- /**
9
- * Resolves the base handler function name for an operation.
10
- *
11
- * @example Resolving handler function names
12
- * `resolver.resolveName('show pet by id') // -> 'showPetByIdHandler'`
13
- */
14
- resolveName(this: ResolverMcp, name: string): string
15
- /**
16
- * Resolves the output file name for an MCP module.
17
- */
18
- resolvePathName(this: ResolverMcp, name: string, type?: 'file' | 'function' | 'type' | 'const'): string
19
- /**
20
- * Resolves the handler function name for an operation.
21
- */
22
- resolveHandlerName(this: ResolverMcp, node: ast.OperationNode): string
23
- }
24
-
25
- export type Options = {
26
- /**
27
- * Where the generated MCP tool handlers are written and how they are exported.
28
- *
29
- * @default { path: 'mcp', barrel: { type: 'named' } }
30
- */
31
- output?: Output
32
- /**
33
- * HTTP client used by each MCP handler to call the underlying API. Mirrors a
34
- * subset of `pluginClient` options.
35
- */
36
- client?: ClientImportPath & Pick<PluginClient['options'], 'clientType' | 'dataReturnType' | 'baseURL' | 'bundle' | 'paramsCasing'>
37
- /**
38
- * Rename parameter properties in the generated handlers. The HTTP layer still
39
- * uses the original spec names; Kubb writes the mapping for you.
40
- *
41
- * @note Must match the value of `paramsCasing` on `@kubb/plugin-ts`.
42
- */
43
- paramsCasing?: 'camelcase'
44
- /**
45
- * Split generated files into subfolders based on the operation's tag.
46
- */
47
- group?: Group
48
- /**
49
- * Skip operations matching at least one entry in the list.
50
- */
51
- exclude?: Array<Exclude>
52
- /**
53
- * Restrict generation to operations matching at least one entry in the list.
54
- */
55
- include?: Array<Include>
56
- /**
57
- * Apply a different options object to operations matching a pattern.
58
- */
59
- override?: Array<Override<ResolvedOptions>>
60
- /**
61
- * Override how handler names and file paths are built. Methods you omit fall
62
- * back to the default `resolverMcp`.
63
- */
64
- resolver?: Partial<ResolverMcp> & ThisType<ResolverMcp>
65
- /**
66
- * AST visitor applied to each operation node before printing.
67
- */
68
- transformer?: ast.Visitor
69
- /**
70
- * Custom generators that run alongside the built-in MCP generators.
71
- */
72
- generators?: Array<Generator<PluginMcp>>
73
- }
74
-
75
- type ResolvedOptions = {
76
- output: Output
77
- exclude: Array<Exclude>
78
- include: Array<Include> | undefined
79
- override: Array<Override<ResolvedOptions>>
80
- group: Group | null
81
- client: Pick<PluginClient['options'], 'client' | 'clientType' | 'dataReturnType' | 'importPath' | 'baseURL' | 'bundle' | 'paramsCasing'>
82
- paramsCasing: Options['paramsCasing']
83
- resolver: ResolverMcp
84
- }
85
-
86
- export type PluginMcp = PluginFactoryOptions<'plugin-mcp', Options, ResolvedOptions, ResolverMcp>
87
-
88
- declare global {
89
- namespace Kubb {
90
- interface PluginRegistry {
91
- 'plugin-mcp': PluginMcp
92
- }
93
- }
94
- }
package/src/utils.ts DELETED
@@ -1,48 +0,0 @@
1
- import type { ast } from '@kubb/core'
2
-
3
- export type ZodParam = {
4
- name: string
5
- schemaName: string
6
- }
7
-
8
- /**
9
- * Render a group param value — compose individual schemas into `z.object({ ... })`,
10
- * or use a schema name string directly.
11
- */
12
- export function zodGroupExpr(entry: string | Array<ZodParam>): string {
13
- if (typeof entry === 'string') {
14
- return entry
15
- }
16
- const entries = entry.map((p) => `${JSON.stringify(p.name)}: ${p.schemaName}`)
17
- return `z.object({ ${entries.join(', ')} })`
18
- }
19
-
20
- /**
21
- * Convert a SchemaNode type to an inline Zod expression string.
22
- * Used as fallback when no named zod schema is available for a path parameter.
23
- */
24
- export function zodExprFromSchemaNode(schema: ast.SchemaNode): string {
25
- const baseExpr = (() => {
26
- if (schema.type === 'enum') {
27
- const rawValues: Array<string | number | boolean> = schema.namedEnumValues?.length
28
- ? schema.namedEnumValues.map((v) => v.value)
29
- : (schema.enumValues ?? []).filter((v): v is string | number | boolean => v !== null)
30
-
31
- if (rawValues.length > 0 && rawValues.every((v) => typeof v === 'string')) {
32
- return `z.enum([${rawValues.map((v) => JSON.stringify(v)).join(', ')}])`
33
- }
34
- if (rawValues.length > 0) {
35
- const literals = rawValues.map((v) => `z.literal(${JSON.stringify(v)})`)
36
- return literals.length === 1 ? literals[0]! : `z.union([${literals.join(', ')}])`
37
- }
38
- return 'z.string()'
39
- }
40
- if (schema.type === 'integer') return 'z.coerce.number()'
41
- if (schema.type === 'number') return 'z.number()'
42
- if (schema.type === 'boolean') return 'z.boolean()'
43
- if (schema.type === 'array') return 'z.array(z.unknown())'
44
- return 'z.string()'
45
- })()
46
-
47
- return schema.nullable ? `${baseExpr}.nullable()` : baseExpr
48
- }