@kubb/plugin-mcp 5.0.0-beta.4 → 5.0.0-beta.42
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/README.md +39 -22
- package/dist/index.cjs +343 -205
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +82 -27
- package/dist/index.js +345 -207
- package/dist/index.js.map +1 -1
- package/extension.yaml +633 -160
- package/package.json +11 -11
- package/src/components/McpHandler.tsx +15 -20
- package/src/components/Server.tsx +76 -71
- package/src/generators/mcpGenerator.tsx +21 -23
- package/src/generators/serverGenerator.tsx +22 -22
- package/src/plugin.ts +38 -18
- package/src/resolvers/resolverMcp.ts +16 -6
- package/src/types.ts +27 -13
- package/src/utils.ts +15 -80
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/src/types.ts
CHANGED
|
@@ -6,54 +6,68 @@ import type { ClientImportPath, PluginClient } from '@kubb/plugin-client'
|
|
|
6
6
|
*/
|
|
7
7
|
export type ResolverMcp = Resolver & {
|
|
8
8
|
/**
|
|
9
|
-
* Resolves the handler function name for an operation.
|
|
9
|
+
* Resolves the base handler function name for an operation.
|
|
10
10
|
*
|
|
11
11
|
* @example Resolving handler function names
|
|
12
12
|
* `resolver.resolveName('show pet by id') // -> 'showPetByIdHandler'`
|
|
13
13
|
*/
|
|
14
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
|
|
15
23
|
}
|
|
16
24
|
|
|
17
25
|
export type Options = {
|
|
18
26
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
27
|
+
* Where the generated MCP tool handlers are written and how they are exported.
|
|
28
|
+
*
|
|
29
|
+
* @default { path: 'mcp', barrel: { type: 'named' } }
|
|
21
30
|
*/
|
|
22
31
|
output?: Output
|
|
23
32
|
/**
|
|
24
|
-
*
|
|
33
|
+
* HTTP client used by each MCP handler to call the underlying API. Mirrors a
|
|
34
|
+
* subset of `pluginClient` options.
|
|
25
35
|
*/
|
|
26
36
|
client?: ClientImportPath & Pick<PluginClient['options'], 'clientType' | 'dataReturnType' | 'baseURL' | 'bundle' | 'paramsCasing'>
|
|
27
37
|
/**
|
|
28
|
-
*
|
|
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`.
|
|
29
42
|
*/
|
|
30
43
|
paramsCasing?: 'camelcase'
|
|
31
44
|
/**
|
|
32
|
-
*
|
|
45
|
+
* Split generated files into subfolders based on the operation's tag.
|
|
33
46
|
*/
|
|
34
47
|
group?: Group
|
|
35
48
|
/**
|
|
36
|
-
*
|
|
49
|
+
* Skip operations matching at least one entry in the list.
|
|
37
50
|
*/
|
|
38
51
|
exclude?: Array<Exclude>
|
|
39
52
|
/**
|
|
40
|
-
*
|
|
53
|
+
* Restrict generation to operations matching at least one entry in the list.
|
|
41
54
|
*/
|
|
42
55
|
include?: Array<Include>
|
|
43
56
|
/**
|
|
44
|
-
*
|
|
57
|
+
* Apply a different options object to operations matching a pattern.
|
|
45
58
|
*/
|
|
46
59
|
override?: Array<Override<ResolvedOptions>>
|
|
47
60
|
/**
|
|
48
|
-
* Override
|
|
61
|
+
* Override how handler names and file paths are built. Methods you omit fall
|
|
62
|
+
* back to the default `resolverMcp`.
|
|
49
63
|
*/
|
|
50
64
|
resolver?: Partial<ResolverMcp> & ThisType<ResolverMcp>
|
|
51
65
|
/**
|
|
52
|
-
* AST visitor to
|
|
66
|
+
* AST visitor applied to each operation node before printing.
|
|
53
67
|
*/
|
|
54
68
|
transformer?: ast.Visitor
|
|
55
69
|
/**
|
|
56
|
-
*
|
|
70
|
+
* Custom generators that run alongside the built-in MCP generators.
|
|
57
71
|
*/
|
|
58
72
|
generators?: Array<Generator<PluginMcp>>
|
|
59
73
|
}
|
|
@@ -63,7 +77,7 @@ type ResolvedOptions = {
|
|
|
63
77
|
exclude: Array<Exclude>
|
|
64
78
|
include: Array<Include> | undefined
|
|
65
79
|
override: Array<Override<ResolvedOptions>>
|
|
66
|
-
group: Group |
|
|
80
|
+
group: Group | null
|
|
67
81
|
client: Pick<PluginClient['options'], 'client' | 'clientType' | 'dataReturnType' | 'importPath' | 'baseURL' | 'bundle' | 'paramsCasing'>
|
|
68
82
|
paramsCasing: Options['paramsCasing']
|
|
69
83
|
resolver: ResolverMcp
|
package/src/utils.ts
CHANGED
|
@@ -1,19 +1,5 @@
|
|
|
1
|
-
import { camelCase } from '@internals/utils'
|
|
2
1
|
import type { ast } from '@kubb/core'
|
|
3
2
|
|
|
4
|
-
/**
|
|
5
|
-
* Find the first 2xx response status code from an operation's responses.
|
|
6
|
-
*/
|
|
7
|
-
export function findSuccessStatusCode(responses: Array<{ statusCode: number | string }>): ast.StatusCode | undefined {
|
|
8
|
-
for (const res of responses) {
|
|
9
|
-
const code = Number(res.statusCode)
|
|
10
|
-
if (code >= 200 && code < 300) {
|
|
11
|
-
return res.statusCode as ast.StatusCode
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
return undefined
|
|
15
|
-
}
|
|
16
|
-
|
|
17
3
|
export type ZodParam = {
|
|
18
4
|
name: string
|
|
19
5
|
schemaName: string
|
|
@@ -31,83 +17,32 @@ export function zodGroupExpr(entry: string | Array<ZodParam>): string {
|
|
|
31
17
|
return `z.object({ ${entries.join(', ')} })`
|
|
32
18
|
}
|
|
33
19
|
|
|
34
|
-
/**
|
|
35
|
-
* Build JSDoc comment lines from an OperationNode.
|
|
36
|
-
*/
|
|
37
|
-
export function getComments(node: ast.OperationNode): Array<string> {
|
|
38
|
-
return [
|
|
39
|
-
node.description && `@description ${node.description}`,
|
|
40
|
-
node.summary && `@summary ${node.summary}`,
|
|
41
|
-
node.deprecated && '@deprecated',
|
|
42
|
-
`{@link ${node.path.replaceAll('{', ':').replaceAll('}', '')}}`,
|
|
43
|
-
].filter((x): x is string => Boolean(x))
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Build a mapping of original param names → camelCase names.
|
|
48
|
-
* Returns `undefined` when no names actually change (no remapping needed).
|
|
49
|
-
*/
|
|
50
|
-
export function getParamsMapping(params: Array<{ name: string }>): Record<string, string> | undefined {
|
|
51
|
-
if (!params.length) {
|
|
52
|
-
return undefined
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const mapping: Record<string, string> = {}
|
|
56
|
-
let hasDifference = false
|
|
57
|
-
|
|
58
|
-
for (const p of params) {
|
|
59
|
-
const camelName = camelCase(p.name)
|
|
60
|
-
mapping[p.name] = camelName
|
|
61
|
-
if (p.name !== camelName) {
|
|
62
|
-
hasDifference = true
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return hasDifference ? mapping : undefined
|
|
67
|
-
}
|
|
68
|
-
|
|
69
20
|
/**
|
|
70
21
|
* Convert a SchemaNode type to an inline Zod expression string.
|
|
71
22
|
* Used as fallback when no named zod schema is available for a path parameter.
|
|
72
23
|
*/
|
|
73
24
|
export function zodExprFromSchemaNode(schema: ast.SchemaNode): string {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
case 'enum': {
|
|
77
|
-
// namedEnumValues takes priority over enumValues
|
|
25
|
+
const baseExpr = (() => {
|
|
26
|
+
if (schema.type === 'enum') {
|
|
78
27
|
const rawValues: Array<string | number | boolean> = schema.namedEnumValues?.length
|
|
79
28
|
? schema.namedEnumValues.map((v) => v.value)
|
|
80
29
|
: (schema.enumValues ?? []).filter((v): v is string | number | boolean => v !== null)
|
|
81
30
|
|
|
82
31
|
if (rawValues.length > 0 && rawValues.every((v) => typeof v === 'string')) {
|
|
83
|
-
|
|
84
|
-
}
|
|
32
|
+
return `z.enum([${rawValues.map((v) => JSON.stringify(v)).join(', ')}])`
|
|
33
|
+
}
|
|
34
|
+
if (rawValues.length > 0) {
|
|
85
35
|
const literals = rawValues.map((v) => `z.literal(${JSON.stringify(v)})`)
|
|
86
|
-
|
|
87
|
-
} else {
|
|
88
|
-
expr = 'z.string()'
|
|
36
|
+
return literals.length === 1 ? literals[0]! : `z.union([${literals.join(', ')}])`
|
|
89
37
|
}
|
|
90
|
-
|
|
38
|
+
return 'z.string()'
|
|
91
39
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
break
|
|
101
|
-
case 'array':
|
|
102
|
-
expr = 'z.array(z.unknown())'
|
|
103
|
-
break
|
|
104
|
-
default:
|
|
105
|
-
expr = 'z.string()'
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
if (schema.nullable) {
|
|
109
|
-
expr = `${expr}.nullable()`
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return expr
|
|
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
|
|
113
48
|
}
|
|
File without changes
|