@kubb/plugin-mcp 5.0.0-beta.10 → 5.0.0-beta.103
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 +22 -25
- package/dist/index.cjs +520 -679
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +171 -134
- package/dist/index.js +498 -656
- package/dist/index.js.map +1 -1
- package/package.json +11 -24
- package/extension.yaml +0 -463
- package/src/components/McpHandler.tsx +0 -167
- package/src/components/Server.tsx +0 -154
- package/src/generators/mcpGenerator.tsx +0 -79
- package/src/generators/serverGenerator.tsx +0 -146
- package/src/index.ts +0 -11
- package/src/plugin.ts +0 -122
- package/src/resolvers/resolverMcp.ts +0 -31
- package/src/types.ts +0 -88
- package/src/utils.ts +0 -64
- /package/dist/{chunk--u3MIqq1.js → rolldown-runtime-C0LytTxp.js} +0 -0
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { getOperationParameters } from '@internals/shared'
|
|
2
|
-
import { ast } from '@kubb/core'
|
|
3
|
-
import { functionPrinter } from '@kubb/plugin-ts'
|
|
4
|
-
import { Const, File, Function } from '@kubb/renderer-jsx'
|
|
5
|
-
import type { KubbReactNode } from '@kubb/renderer-jsx/types'
|
|
6
|
-
import type { PluginMcp } from '../types.ts'
|
|
7
|
-
import type { ZodParam } from '../utils.ts'
|
|
8
|
-
import { zodExprFromSchemaNode, zodGroupExpr } from '../utils.ts'
|
|
9
|
-
|
|
10
|
-
type Props = {
|
|
11
|
-
/**
|
|
12
|
-
* Variable name for the MCP server instance (e.g. 'server').
|
|
13
|
-
*/
|
|
14
|
-
name: string
|
|
15
|
-
/**
|
|
16
|
-
* Human-readable server name passed to `new McpServer({ name })`.
|
|
17
|
-
*/
|
|
18
|
-
serverName: string
|
|
19
|
-
/**
|
|
20
|
-
* Semantic version string passed to `new McpServer({ version })`.
|
|
21
|
-
*/
|
|
22
|
-
serverVersion: string
|
|
23
|
-
/**
|
|
24
|
-
* How to style your params.
|
|
25
|
-
*/
|
|
26
|
-
paramsCasing?: PluginMcp['resolvedOptions']['paramsCasing']
|
|
27
|
-
/**
|
|
28
|
-
* Operations to register as MCP tools, each carrying its handler,
|
|
29
|
-
* zod schema, and AST node metadata.
|
|
30
|
-
*/
|
|
31
|
-
operations: Array<{
|
|
32
|
-
tool: {
|
|
33
|
-
name: string
|
|
34
|
-
title?: string
|
|
35
|
-
description: string
|
|
36
|
-
}
|
|
37
|
-
mcp: {
|
|
38
|
-
name: string
|
|
39
|
-
file: ast.FileNode
|
|
40
|
-
}
|
|
41
|
-
zod: {
|
|
42
|
-
pathParams: Array<ZodParam>
|
|
43
|
-
/**
|
|
44
|
-
* Query params — individual schemas to compose into `z.object({ ... })`.
|
|
45
|
-
*/
|
|
46
|
-
queryParams?: string | Array<ZodParam>
|
|
47
|
-
/**
|
|
48
|
-
* Header params — individual schemas to compose into `z.object({ ... })`.
|
|
49
|
-
*/
|
|
50
|
-
headerParams?: string | Array<ZodParam>
|
|
51
|
-
requestName?: string
|
|
52
|
-
responseName?: string
|
|
53
|
-
}
|
|
54
|
-
node: ast.OperationNode
|
|
55
|
-
}>
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const keysPrinter = functionPrinter({ mode: 'keys' })
|
|
59
|
-
|
|
60
|
-
export function Server({ name, serverName, serverVersion, paramsCasing, operations }: Props): KubbReactNode {
|
|
61
|
-
return (
|
|
62
|
-
<File.Source name={name} isExportable isIndexable>
|
|
63
|
-
<Const name={'server'} export>
|
|
64
|
-
{`
|
|
65
|
-
new McpServer({
|
|
66
|
-
name: '${serverName}',
|
|
67
|
-
version: '${serverVersion}',
|
|
68
|
-
})
|
|
69
|
-
`}
|
|
70
|
-
</Const>
|
|
71
|
-
|
|
72
|
-
{operations
|
|
73
|
-
.map(({ tool, mcp, zod, node }) => {
|
|
74
|
-
const { path: pathParams } = getOperationParameters(node, { paramsCasing })
|
|
75
|
-
|
|
76
|
-
const pathEntries: Array<{ key: string; value: string }> = []
|
|
77
|
-
const otherEntries: Array<{ key: string; value: string }> = []
|
|
78
|
-
|
|
79
|
-
for (const p of pathParams) {
|
|
80
|
-
const zodParam = zod.pathParams.find((zp) => zp.name === p.name)
|
|
81
|
-
pathEntries.push({ key: p.name, value: zodParam ? zodParam.schemaName : zodExprFromSchemaNode(p.schema) })
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (zod.requestName) {
|
|
85
|
-
otherEntries.push({ key: 'data', value: zod.requestName })
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (zod.queryParams) {
|
|
89
|
-
otherEntries.push({ key: 'params', value: zodGroupExpr(zod.queryParams) })
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (zod.headerParams) {
|
|
93
|
-
otherEntries.push({ key: 'headers', value: zodGroupExpr(zod.headerParams) })
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
otherEntries.sort((a, b) => a.key.localeCompare(b.key))
|
|
97
|
-
const entries = [...pathEntries, ...otherEntries]
|
|
98
|
-
|
|
99
|
-
const paramsNode = entries.length
|
|
100
|
-
? ast.createFunctionParameters({
|
|
101
|
-
params: [
|
|
102
|
-
ast.createParameterGroup({
|
|
103
|
-
properties: entries.map((e) => ast.createFunctionParameter({ name: e.key, optional: false })),
|
|
104
|
-
}),
|
|
105
|
-
],
|
|
106
|
-
})
|
|
107
|
-
: undefined
|
|
108
|
-
|
|
109
|
-
const destructured = paramsNode ? (keysPrinter.print(paramsNode) ?? '') : ''
|
|
110
|
-
const inputSchema = entries.length ? `{ ${entries.map((e) => `${e.key}: ${e.value}`).join(', ')} }` : undefined
|
|
111
|
-
const outputSchema = zod.responseName
|
|
112
|
-
|
|
113
|
-
const config = [
|
|
114
|
-
tool.title ? `title: ${JSON.stringify(tool.title)}` : null,
|
|
115
|
-
`description: ${JSON.stringify(tool.description)}`,
|
|
116
|
-
outputSchema ? `outputSchema: { data: ${outputSchema} }` : null,
|
|
117
|
-
]
|
|
118
|
-
.filter(Boolean)
|
|
119
|
-
.join(',\n ')
|
|
120
|
-
|
|
121
|
-
if (inputSchema) {
|
|
122
|
-
return `
|
|
123
|
-
server.registerTool(${JSON.stringify(tool.name)}, {
|
|
124
|
-
${config},
|
|
125
|
-
inputSchema: ${inputSchema},
|
|
126
|
-
}, async (${destructured}, request) => {
|
|
127
|
-
return ${mcp.name}(${destructured}, request)
|
|
128
|
-
})
|
|
129
|
-
`
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
return `
|
|
133
|
-
server.registerTool(${JSON.stringify(tool.name)}, {
|
|
134
|
-
${config},
|
|
135
|
-
}, async (request) => {
|
|
136
|
-
return ${mcp.name}(request)
|
|
137
|
-
})
|
|
138
|
-
`
|
|
139
|
-
})
|
|
140
|
-
.filter(Boolean)}
|
|
141
|
-
|
|
142
|
-
<Function name="startServer" async export>
|
|
143
|
-
{`try {
|
|
144
|
-
const transport = new StdioServerTransport()
|
|
145
|
-
await server.connect(transport)
|
|
146
|
-
|
|
147
|
-
} catch (error) {
|
|
148
|
-
console.error('Failed to start server:', error)
|
|
149
|
-
process.exit(1)
|
|
150
|
-
}`}
|
|
151
|
-
</Function>
|
|
152
|
-
</File.Source>
|
|
153
|
-
)
|
|
154
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import { resolveOperationTypeNames } from '@internals/shared'
|
|
3
|
-
import { defineGenerator } from '@kubb/core'
|
|
4
|
-
import { pluginTsName } from '@kubb/plugin-ts'
|
|
5
|
-
import { File, jsxRenderer } from '@kubb/renderer-jsx'
|
|
6
|
-
import { McpHandler } from '../components/McpHandler.tsx'
|
|
7
|
-
import type { PluginMcp } from '../types.ts'
|
|
8
|
-
|
|
9
|
-
export const mcpGenerator = defineGenerator<PluginMcp>({
|
|
10
|
-
name: 'mcp',
|
|
11
|
-
renderer: jsxRenderer,
|
|
12
|
-
operation(node, ctx) {
|
|
13
|
-
const { resolver, driver, root } = ctx
|
|
14
|
-
const { output, client, paramsCasing, group } = ctx.options
|
|
15
|
-
|
|
16
|
-
const pluginTs = driver.getPlugin(pluginTsName)
|
|
17
|
-
|
|
18
|
-
if (!pluginTs) {
|
|
19
|
-
return null
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const tsResolver = driver.getResolver(pluginTsName)
|
|
23
|
-
|
|
24
|
-
const importedTypeNames = resolveOperationTypeNames(node, tsResolver, { paramsCasing, responseStatusNames: 'error' })
|
|
25
|
-
|
|
26
|
-
const meta = {
|
|
27
|
-
name: resolver.resolveHandlerName(node),
|
|
28
|
-
file: resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group }),
|
|
29
|
-
fileTs: tsResolver.resolveFile(
|
|
30
|
-
{ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
|
|
31
|
-
{
|
|
32
|
-
root,
|
|
33
|
-
output: pluginTs.options?.output ?? output,
|
|
34
|
-
group: pluginTs.options?.group,
|
|
35
|
-
},
|
|
36
|
-
),
|
|
37
|
-
} as const
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<File baseName={meta.file.baseName} path={meta.file.path} meta={meta.file.meta}>
|
|
41
|
-
{meta.fileTs && importedTypeNames.length > 0 && (
|
|
42
|
-
<File.Import name={Array.from(new Set(importedTypeNames)).sort()} root={meta.file.path} path={meta.fileTs.path} isTypeOnly />
|
|
43
|
-
)}
|
|
44
|
-
<File.Import name={['CallToolResult', 'ServerNotification', 'ServerRequest']} path={'@modelcontextprotocol/sdk/types'} isTypeOnly />
|
|
45
|
-
<File.Import name={['RequestHandlerExtra']} path={'@modelcontextprotocol/sdk/shared/protocol'} isTypeOnly />
|
|
46
|
-
<File.Import name={['buildFormData']} root={meta.file.path} path={path.resolve(root, '.kubb/config.ts')} />
|
|
47
|
-
{client.importPath ? (
|
|
48
|
-
<>
|
|
49
|
-
<File.Import name={['Client', 'RequestConfig', 'ResponseErrorConfig']} path={client.importPath} isTypeOnly />
|
|
50
|
-
<File.Import name={'fetch'} path={client.importPath} />
|
|
51
|
-
{client.dataReturnType === 'full' && <File.Import name={['ResponseConfig']} path={client.importPath} isTypeOnly />}
|
|
52
|
-
</>
|
|
53
|
-
) : (
|
|
54
|
-
<>
|
|
55
|
-
<File.Import
|
|
56
|
-
name={['Client', 'RequestConfig', 'ResponseErrorConfig']}
|
|
57
|
-
root={meta.file.path}
|
|
58
|
-
path={path.resolve(root, '.kubb/fetch.ts')}
|
|
59
|
-
isTypeOnly
|
|
60
|
-
/>
|
|
61
|
-
<File.Import name={['fetch']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} />
|
|
62
|
-
{client.dataReturnType === 'full' && (
|
|
63
|
-
<File.Import name={['ResponseConfig']} root={meta.file.path} path={path.resolve(root, '.kubb/fetch.ts')} isTypeOnly />
|
|
64
|
-
)}
|
|
65
|
-
</>
|
|
66
|
-
)}
|
|
67
|
-
|
|
68
|
-
<McpHandler
|
|
69
|
-
name={meta.name}
|
|
70
|
-
node={node}
|
|
71
|
-
resolver={tsResolver}
|
|
72
|
-
baseURL={client.baseURL}
|
|
73
|
-
dataReturnType={client.dataReturnType || 'data'}
|
|
74
|
-
paramsCasing={paramsCasing}
|
|
75
|
-
/>
|
|
76
|
-
</File>
|
|
77
|
-
)
|
|
78
|
-
},
|
|
79
|
-
})
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import { findSuccessStatusCode, getOperationParameters } from '@internals/shared'
|
|
3
|
-
import { defineGenerator } from '@kubb/core'
|
|
4
|
-
import { pluginZodName } from '@kubb/plugin-zod'
|
|
5
|
-
import { File, jsxRenderer } from '@kubb/renderer-jsx'
|
|
6
|
-
import { Server } from '../components/Server.tsx'
|
|
7
|
-
import type { PluginMcp } from '../types.ts'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Default v5 server generator for `@kubb/plugin-mcp`.
|
|
11
|
-
*
|
|
12
|
-
* Uses individual zod schemas for each param (e.g. `createPetsPathUuidSchema`, `createPetsQueryOffsetSchema`)
|
|
13
|
-
* and `resolveResponseStatusName` for per-status response schemas.
|
|
14
|
-
* Query and header params are composed into `z.object({ ... })` from individual schemas.
|
|
15
|
-
*/
|
|
16
|
-
export const serverGenerator = defineGenerator<PluginMcp>({
|
|
17
|
-
name: 'operations',
|
|
18
|
-
renderer: jsxRenderer,
|
|
19
|
-
operations(nodes, ctx) {
|
|
20
|
-
const { adapter, config, resolver, plugin, driver, root } = ctx
|
|
21
|
-
const { output, paramsCasing, group } = ctx.options
|
|
22
|
-
|
|
23
|
-
const pluginZod = driver.getPlugin(pluginZodName)
|
|
24
|
-
|
|
25
|
-
if (!pluginZod) {
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const zodResolver = driver.getResolver(pluginZodName)
|
|
30
|
-
|
|
31
|
-
const name = 'server'
|
|
32
|
-
const serverFilePath = path.resolve(root, output.path, 'server.ts')
|
|
33
|
-
const serverFile = {
|
|
34
|
-
baseName: 'server.ts' as const,
|
|
35
|
-
path: serverFilePath,
|
|
36
|
-
meta: { pluginName: plugin.name },
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const jsonFilePath = path.resolve(root, output.path, '.mcp.json')
|
|
40
|
-
const jsonFile = {
|
|
41
|
-
baseName: '.mcp.json' as const,
|
|
42
|
-
path: jsonFilePath,
|
|
43
|
-
meta: { pluginName: plugin.name },
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const operationsMapped = nodes.map((node) => {
|
|
47
|
-
const { path: pathParams, query: queryParams, header: headerParams } = getOperationParameters(node, { paramsCasing })
|
|
48
|
-
|
|
49
|
-
const mcpFile = resolver.resolveFile({ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path }, { root, output, group })
|
|
50
|
-
|
|
51
|
-
const zodFile = zodResolver.resolveFile(
|
|
52
|
-
{ name: node.operationId, extname: '.ts', tag: node.tags[0] ?? 'default', path: node.path },
|
|
53
|
-
{
|
|
54
|
-
root,
|
|
55
|
-
output: pluginZod.options?.output ?? output,
|
|
56
|
-
group: pluginZod.options?.group,
|
|
57
|
-
},
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
const requestName = node.requestBody?.content?.[0]?.schema ? zodResolver.resolveDataName(node) : undefined
|
|
61
|
-
const successStatus = findSuccessStatusCode(node.responses)
|
|
62
|
-
const responseName = successStatus ? zodResolver.resolveResponseStatusName(node, successStatus) : undefined
|
|
63
|
-
|
|
64
|
-
const resolveParams = (params: typeof pathParams) => params.map((p) => ({ name: p.name, schemaName: zodResolver.resolveParamName(node, p) }))
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
tool: {
|
|
68
|
-
name: node.operationId,
|
|
69
|
-
title: node.summary || undefined,
|
|
70
|
-
description: node.description || `Make a ${node.method.toUpperCase()} request to ${node.path}`,
|
|
71
|
-
},
|
|
72
|
-
mcp: {
|
|
73
|
-
name: resolver.resolveHandlerName(node),
|
|
74
|
-
file: mcpFile,
|
|
75
|
-
},
|
|
76
|
-
zod: {
|
|
77
|
-
pathParams: resolveParams(pathParams),
|
|
78
|
-
queryParams: queryParams.length ? resolveParams(queryParams) : undefined,
|
|
79
|
-
headerParams: headerParams.length ? resolveParams(headerParams) : undefined,
|
|
80
|
-
requestName,
|
|
81
|
-
responseName,
|
|
82
|
-
file: zodFile,
|
|
83
|
-
},
|
|
84
|
-
node: node,
|
|
85
|
-
}
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
const imports = operationsMapped.flatMap(({ mcp, zod }) => {
|
|
89
|
-
const zodNames = [
|
|
90
|
-
...zod.pathParams.map((p) => p.schemaName),
|
|
91
|
-
...(zod.queryParams ?? []).map((p) => p.schemaName),
|
|
92
|
-
...(zod.headerParams ?? []).map((p) => p.schemaName),
|
|
93
|
-
zod.requestName,
|
|
94
|
-
zod.responseName,
|
|
95
|
-
].filter((name): name is string => Boolean(name))
|
|
96
|
-
|
|
97
|
-
const uniqueNames = [...new Set(zodNames)].sort()
|
|
98
|
-
|
|
99
|
-
return [
|
|
100
|
-
<File.Import key={mcp.name} name={[mcp.name]} root={serverFile.path} path={mcp.file.path} />,
|
|
101
|
-
uniqueNames.length > 0 && <File.Import key={`zod-${mcp.name}`} name={uniqueNames} root={serverFile.path} path={zod.file.path} />,
|
|
102
|
-
].filter(Boolean)
|
|
103
|
-
})
|
|
104
|
-
|
|
105
|
-
return (
|
|
106
|
-
<>
|
|
107
|
-
<File
|
|
108
|
-
baseName={serverFile.baseName}
|
|
109
|
-
path={serverFile.path}
|
|
110
|
-
meta={serverFile.meta}
|
|
111
|
-
banner={resolver.resolveBanner(adapter.inputNode, { output, config })}
|
|
112
|
-
footer={resolver.resolveFooter(adapter.inputNode, { output, config })}
|
|
113
|
-
>
|
|
114
|
-
<File.Import name={['McpServer']} path={'@modelcontextprotocol/sdk/server/mcp'} />
|
|
115
|
-
<File.Import name={['z']} path={'zod'} />
|
|
116
|
-
<File.Import name={['StdioServerTransport']} path={'@modelcontextprotocol/sdk/server/stdio'} />
|
|
117
|
-
|
|
118
|
-
{imports}
|
|
119
|
-
<Server
|
|
120
|
-
name={name}
|
|
121
|
-
serverName={adapter.inputNode?.meta?.title ?? 'server'}
|
|
122
|
-
serverVersion={adapter.inputNode?.meta?.version ?? '0.0.0'}
|
|
123
|
-
paramsCasing={paramsCasing}
|
|
124
|
-
operations={operationsMapped}
|
|
125
|
-
/>
|
|
126
|
-
</File>
|
|
127
|
-
|
|
128
|
-
<File baseName={jsonFile.baseName} path={jsonFile.path} meta={jsonFile.meta}>
|
|
129
|
-
<File.Source name={name}>
|
|
130
|
-
{`
|
|
131
|
-
{
|
|
132
|
-
"mcpServers": {
|
|
133
|
-
"${adapter.inputNode?.meta?.title || 'server'}": {
|
|
134
|
-
"type": "stdio",
|
|
135
|
-
"command": "npx",
|
|
136
|
-
"args": ["tsx", "${path.relative(path.dirname(jsonFile.path), serverFile.path)}"]
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
`}
|
|
141
|
-
</File.Source>
|
|
142
|
-
</File>
|
|
143
|
-
</>
|
|
144
|
-
)
|
|
145
|
-
},
|
|
146
|
-
})
|
package/src/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export { McpHandler } from './components/McpHandler.tsx'
|
|
2
|
-
export { Server } from './components/Server.tsx'
|
|
3
|
-
|
|
4
|
-
export { mcpGenerator } from './generators/mcpGenerator.tsx'
|
|
5
|
-
export { serverGenerator } from './generators/serverGenerator.tsx'
|
|
6
|
-
|
|
7
|
-
export { default, pluginMcp, pluginMcpName } from './plugin.ts'
|
|
8
|
-
|
|
9
|
-
export { resolverMcp } from './resolvers/resolverMcp.ts'
|
|
10
|
-
|
|
11
|
-
export type { PluginMcp, ResolverMcp } from './types.ts'
|
package/src/plugin.ts
DELETED
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import path from 'node:path'
|
|
2
|
-
import { camelCase } from '@internals/utils'
|
|
3
|
-
|
|
4
|
-
import { ast, definePlugin, type Group } 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
|
-
export const pluginMcpName = 'plugin-mcp' satisfies PluginMcp['name']
|
|
17
|
-
|
|
18
|
-
export const pluginMcp = definePlugin<PluginMcp>((options) => {
|
|
19
|
-
const {
|
|
20
|
-
output = { path: 'mcp', barrelType: 'named' },
|
|
21
|
-
group,
|
|
22
|
-
exclude = [],
|
|
23
|
-
include,
|
|
24
|
-
override = [],
|
|
25
|
-
paramsCasing,
|
|
26
|
-
client,
|
|
27
|
-
resolver: userResolver,
|
|
28
|
-
transformer: userTransformer,
|
|
29
|
-
generators: userGenerators = [],
|
|
30
|
-
} = options
|
|
31
|
-
|
|
32
|
-
const clientName = client?.client ?? 'axios'
|
|
33
|
-
const clientImportPath = client?.importPath ?? (!client?.bundle ? `@kubb/plugin-client/clients/${clientName}` : undefined)
|
|
34
|
-
|
|
35
|
-
const groupConfig = group
|
|
36
|
-
? ({
|
|
37
|
-
...group,
|
|
38
|
-
name: group.name
|
|
39
|
-
? group.name
|
|
40
|
-
: (ctx: { group: string }) => {
|
|
41
|
-
if (group.type === 'path') {
|
|
42
|
-
return `${ctx.group.split('/')[1]}`
|
|
43
|
-
}
|
|
44
|
-
return `${camelCase(ctx.group)}Requests`
|
|
45
|
-
},
|
|
46
|
-
} satisfies Group)
|
|
47
|
-
: undefined
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
name: pluginMcpName,
|
|
51
|
-
options,
|
|
52
|
-
dependencies: [pluginTsName, pluginZodName],
|
|
53
|
-
hooks: {
|
|
54
|
-
'kubb:plugin:setup'(ctx) {
|
|
55
|
-
const resolver = userResolver ? { ...resolverMcp, ...userResolver } : resolverMcp
|
|
56
|
-
|
|
57
|
-
ctx.setOptions({
|
|
58
|
-
output,
|
|
59
|
-
exclude,
|
|
60
|
-
include,
|
|
61
|
-
override,
|
|
62
|
-
group: groupConfig,
|
|
63
|
-
paramsCasing,
|
|
64
|
-
client: {
|
|
65
|
-
client: clientName,
|
|
66
|
-
clientType: client?.clientType ?? 'function',
|
|
67
|
-
importPath: clientImportPath,
|
|
68
|
-
dataReturnType: client?.dataReturnType ?? 'data',
|
|
69
|
-
bundle: client?.bundle,
|
|
70
|
-
baseURL: client?.baseURL,
|
|
71
|
-
paramsCasing: client?.paramsCasing,
|
|
72
|
-
},
|
|
73
|
-
resolver,
|
|
74
|
-
})
|
|
75
|
-
ctx.setResolver(resolver)
|
|
76
|
-
if (userTransformer) {
|
|
77
|
-
ctx.setTransformer(userTransformer)
|
|
78
|
-
}
|
|
79
|
-
ctx.addGenerator(mcpGenerator)
|
|
80
|
-
ctx.addGenerator(serverGenerator)
|
|
81
|
-
for (const gen of userGenerators) {
|
|
82
|
-
ctx.addGenerator(gen)
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const root = path.resolve(ctx.config.root, ctx.config.output.path)
|
|
86
|
-
const hasClientPlugin = ctx.config.plugins?.some((p) => p.name === pluginClientName)
|
|
87
|
-
|
|
88
|
-
if (client?.bundle && !hasClientPlugin && !clientImportPath) {
|
|
89
|
-
ctx.injectFile({
|
|
90
|
-
baseName: 'fetch.ts',
|
|
91
|
-
path: path.resolve(root, '.kubb/fetch.ts'),
|
|
92
|
-
sources: [
|
|
93
|
-
ast.createSource({
|
|
94
|
-
name: 'fetch',
|
|
95
|
-
nodes: [ast.createText(clientName === 'fetch' ? fetchClientSource : axiosClientSource)],
|
|
96
|
-
isExportable: true,
|
|
97
|
-
isIndexable: true,
|
|
98
|
-
}),
|
|
99
|
-
],
|
|
100
|
-
})
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (!hasClientPlugin) {
|
|
104
|
-
ctx.injectFile({
|
|
105
|
-
baseName: 'config.ts',
|
|
106
|
-
path: path.resolve(root, '.kubb/config.ts'),
|
|
107
|
-
sources: [
|
|
108
|
-
ast.createSource({
|
|
109
|
-
name: 'config',
|
|
110
|
-
nodes: [ast.createText(configSource)],
|
|
111
|
-
isExportable: false,
|
|
112
|
-
isIndexable: false,
|
|
113
|
-
}),
|
|
114
|
-
],
|
|
115
|
-
})
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
}
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
export default pluginMcp
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { camelCase } from '@internals/utils'
|
|
2
|
-
import { defineResolver } from '@kubb/core'
|
|
3
|
-
import type { PluginMcp } from '../types.ts'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Naming convention resolver for MCP plugin.
|
|
7
|
-
*
|
|
8
|
-
* Provides default naming helpers using camelCase with a `handler` suffix for functions.
|
|
9
|
-
*
|
|
10
|
-
* @example
|
|
11
|
-
* `resolverMcp.default('addPet', 'function') // → 'addPetHandler'`
|
|
12
|
-
*/
|
|
13
|
-
export const resolverMcp = defineResolver<PluginMcp>(() => ({
|
|
14
|
-
name: 'default',
|
|
15
|
-
pluginName: 'plugin-mcp',
|
|
16
|
-
default(name, type) {
|
|
17
|
-
if (type === 'file') {
|
|
18
|
-
return camelCase(name, { isFile: true })
|
|
19
|
-
}
|
|
20
|
-
return camelCase(name, { suffix: 'handler' })
|
|
21
|
-
},
|
|
22
|
-
resolveName(name) {
|
|
23
|
-
return this.default(name, 'function')
|
|
24
|
-
},
|
|
25
|
-
resolvePathName(name, type) {
|
|
26
|
-
return this.default(name, type)
|
|
27
|
-
},
|
|
28
|
-
resolveHandlerName(node) {
|
|
29
|
-
return this.resolveName(node.operationId)
|
|
30
|
-
},
|
|
31
|
-
}))
|
package/src/types.ts
DELETED
|
@@ -1,88 +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
|
-
* Specify the export location for the files and define the behavior of the output.
|
|
28
|
-
* @default { path: 'mcp', barrelType: 'named' }
|
|
29
|
-
*/
|
|
30
|
-
output?: Output
|
|
31
|
-
/**
|
|
32
|
-
* Client configuration for HTTP request generation.
|
|
33
|
-
*/
|
|
34
|
-
client?: ClientImportPath & Pick<PluginClient['options'], 'clientType' | 'dataReturnType' | 'baseURL' | 'bundle' | 'paramsCasing'>
|
|
35
|
-
/**
|
|
36
|
-
* Apply casing to parameter names to match your configuration.
|
|
37
|
-
*/
|
|
38
|
-
paramsCasing?: 'camelcase'
|
|
39
|
-
/**
|
|
40
|
-
* Group the MCP requests based on the provided name.
|
|
41
|
-
*/
|
|
42
|
-
group?: Group
|
|
43
|
-
/**
|
|
44
|
-
* Tags, operations, or paths to exclude from generation.
|
|
45
|
-
*/
|
|
46
|
-
exclude?: Array<Exclude>
|
|
47
|
-
/**
|
|
48
|
-
* Tags, operations, or paths to include in generation.
|
|
49
|
-
*/
|
|
50
|
-
include?: Array<Include>
|
|
51
|
-
/**
|
|
52
|
-
* Override options for specific tags, operations, or paths.
|
|
53
|
-
*/
|
|
54
|
-
override?: Array<Override<ResolvedOptions>>
|
|
55
|
-
/**
|
|
56
|
-
* Override naming conventions for function names and types.
|
|
57
|
-
*/
|
|
58
|
-
resolver?: Partial<ResolverMcp> & ThisType<ResolverMcp>
|
|
59
|
-
/**
|
|
60
|
-
* AST visitor to transform generated nodes.
|
|
61
|
-
*/
|
|
62
|
-
transformer?: ast.Visitor
|
|
63
|
-
/**
|
|
64
|
-
* Additional generators alongside the default generators.
|
|
65
|
-
*/
|
|
66
|
-
generators?: Array<Generator<PluginMcp>>
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
type ResolvedOptions = {
|
|
70
|
-
output: Output
|
|
71
|
-
exclude: Array<Exclude>
|
|
72
|
-
include: Array<Include> | undefined
|
|
73
|
-
override: Array<Override<ResolvedOptions>>
|
|
74
|
-
group: Group | undefined
|
|
75
|
-
client: Pick<PluginClient['options'], 'client' | 'clientType' | 'dataReturnType' | 'importPath' | 'baseURL' | 'bundle' | 'paramsCasing'>
|
|
76
|
-
paramsCasing: Options['paramsCasing']
|
|
77
|
-
resolver: ResolverMcp
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export type PluginMcp = PluginFactoryOptions<'plugin-mcp', Options, ResolvedOptions, ResolverMcp>
|
|
81
|
-
|
|
82
|
-
declare global {
|
|
83
|
-
namespace Kubb {
|
|
84
|
-
interface PluginRegistry {
|
|
85
|
-
'plugin-mcp': PluginMcp
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|