@kubb/plugin-mcp 0.0.0-canary-20250414193247
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/LICENSE +21 -0
- package/README.md +53 -0
- package/dist/chunk-5AJXTSAA.cjs +179 -0
- package/dist/chunk-5AJXTSAA.cjs.map +1 -0
- package/dist/chunk-RN55DM2O.cjs +97 -0
- package/dist/chunk-RN55DM2O.cjs.map +1 -0
- package/dist/chunk-VPK2OEBV.js +95 -0
- package/dist/chunk-VPK2OEBV.js.map +1 -0
- package/dist/chunk-WEY2R35B.js +176 -0
- package/dist/chunk-WEY2R35B.js.map +1 -0
- package/dist/components.cjs +12 -0
- package/dist/components.cjs.map +1 -0
- package/dist/components.d.cts +27 -0
- package/dist/components.d.ts +27 -0
- package/dist/components.js +3 -0
- package/dist/components.js.map +1 -0
- package/dist/generators.cjs +17 -0
- package/dist/generators.cjs.map +1 -0
- package/dist/generators.d.cts +11 -0
- package/dist/generators.d.ts +11 -0
- package/dist/generators.js +4 -0
- package/dist/generators.js.map +1 -0
- package/dist/index.cjs +108 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +101 -0
- package/dist/index.js.map +1 -0
- package/dist/types-B4DlUSkU.d.cts +54 -0
- package/dist/types-B4DlUSkU.d.ts +54 -0
- package/package.json +117 -0
- package/src/components/Server.tsx +141 -0
- package/src/components/index.ts +1 -0
- package/src/generators/__snapshots__/.mcp.json +9 -0
- package/src/generators/__snapshots__/createPet.ts +19 -0
- package/src/generators/__snapshots__/deletePet.ts +18 -0
- package/src/generators/__snapshots__/getPets.ts +19 -0
- package/src/generators/__snapshots__/server.ts +37 -0
- package/src/generators/__snapshots__/showPetById.ts +25 -0
- package/src/generators/index.ts +2 -0
- package/src/generators/mcpGenerator.tsx +89 -0
- package/src/generators/serverGenerator.tsx +93 -0
- package/src/index.ts +2 -0
- package/src/plugin.ts +120 -0
- package/src/types.ts +54 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Output, Group, PluginFactoryOptions, ResolveNameParams } from '@kubb/core';
|
|
2
|
+
import { Oas, contentType } from '@kubb/oas';
|
|
3
|
+
import { Exclude, Include, Override, ResolvePathOptions, Generator } from '@kubb/plugin-oas';
|
|
4
|
+
import { PluginClient } from '@kubb/plugin-client';
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
/**
|
|
8
|
+
* Specify the export location for the files and define the behavior of the output
|
|
9
|
+
* @default { path: 'mcp', barrelType: 'named' }
|
|
10
|
+
*/
|
|
11
|
+
output?: Output<Oas>;
|
|
12
|
+
/**
|
|
13
|
+
* Define which contentType should be used.
|
|
14
|
+
* By default, the first JSON valid mediaType will be used
|
|
15
|
+
*/
|
|
16
|
+
contentType?: contentType;
|
|
17
|
+
client?: Pick<PluginClient['options'], 'dataReturnType' | 'importPath' | 'baseURL'>;
|
|
18
|
+
/**
|
|
19
|
+
* Group the mcp requests based on the provided name.
|
|
20
|
+
*/
|
|
21
|
+
group?: Group;
|
|
22
|
+
/**
|
|
23
|
+
* Array containing exclude parameters to exclude/skip tags/operations/methods/paths.
|
|
24
|
+
*/
|
|
25
|
+
exclude?: Array<Exclude>;
|
|
26
|
+
/**
|
|
27
|
+
* Array containing include parameters to include tags/operations/methods/paths.
|
|
28
|
+
*/
|
|
29
|
+
include?: Array<Include>;
|
|
30
|
+
/**
|
|
31
|
+
* Array containing override parameters to override `options` based on tags/operations/methods/paths.
|
|
32
|
+
*/
|
|
33
|
+
override?: Array<Override<ResolvedOptions>>;
|
|
34
|
+
transformers?: {
|
|
35
|
+
/**
|
|
36
|
+
* Customize the names based on the type that is provided by the plugin.
|
|
37
|
+
*/
|
|
38
|
+
name?: (name: ResolveNameParams['name'], type?: ResolveNameParams['type']) => string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Define some generators next to the Mcp generators.
|
|
42
|
+
*/
|
|
43
|
+
generators?: Array<Generator<PluginMcp>>;
|
|
44
|
+
};
|
|
45
|
+
type ResolvedOptions = {
|
|
46
|
+
output: Output<Oas>;
|
|
47
|
+
group: Options['group'];
|
|
48
|
+
client: Required<Omit<NonNullable<PluginMcp['options']['client']>, 'baseURL'>> & {
|
|
49
|
+
baseURL?: string;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
type PluginMcp = PluginFactoryOptions<'plugin-mcp', Options, ResolvedOptions, never, ResolvePathOptions>;
|
|
53
|
+
|
|
54
|
+
export type { Options as O, PluginMcp as P };
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Output, Group, PluginFactoryOptions, ResolveNameParams } from '@kubb/core';
|
|
2
|
+
import { Oas, contentType } from '@kubb/oas';
|
|
3
|
+
import { Exclude, Include, Override, ResolvePathOptions, Generator } from '@kubb/plugin-oas';
|
|
4
|
+
import { PluginClient } from '@kubb/plugin-client';
|
|
5
|
+
|
|
6
|
+
type Options = {
|
|
7
|
+
/**
|
|
8
|
+
* Specify the export location for the files and define the behavior of the output
|
|
9
|
+
* @default { path: 'mcp', barrelType: 'named' }
|
|
10
|
+
*/
|
|
11
|
+
output?: Output<Oas>;
|
|
12
|
+
/**
|
|
13
|
+
* Define which contentType should be used.
|
|
14
|
+
* By default, the first JSON valid mediaType will be used
|
|
15
|
+
*/
|
|
16
|
+
contentType?: contentType;
|
|
17
|
+
client?: Pick<PluginClient['options'], 'dataReturnType' | 'importPath' | 'baseURL'>;
|
|
18
|
+
/**
|
|
19
|
+
* Group the mcp requests based on the provided name.
|
|
20
|
+
*/
|
|
21
|
+
group?: Group;
|
|
22
|
+
/**
|
|
23
|
+
* Array containing exclude parameters to exclude/skip tags/operations/methods/paths.
|
|
24
|
+
*/
|
|
25
|
+
exclude?: Array<Exclude>;
|
|
26
|
+
/**
|
|
27
|
+
* Array containing include parameters to include tags/operations/methods/paths.
|
|
28
|
+
*/
|
|
29
|
+
include?: Array<Include>;
|
|
30
|
+
/**
|
|
31
|
+
* Array containing override parameters to override `options` based on tags/operations/methods/paths.
|
|
32
|
+
*/
|
|
33
|
+
override?: Array<Override<ResolvedOptions>>;
|
|
34
|
+
transformers?: {
|
|
35
|
+
/**
|
|
36
|
+
* Customize the names based on the type that is provided by the plugin.
|
|
37
|
+
*/
|
|
38
|
+
name?: (name: ResolveNameParams['name'], type?: ResolveNameParams['type']) => string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Define some generators next to the Mcp generators.
|
|
42
|
+
*/
|
|
43
|
+
generators?: Array<Generator<PluginMcp>>;
|
|
44
|
+
};
|
|
45
|
+
type ResolvedOptions = {
|
|
46
|
+
output: Output<Oas>;
|
|
47
|
+
group: Options['group'];
|
|
48
|
+
client: Required<Omit<NonNullable<PluginMcp['options']['client']>, 'baseURL'>> & {
|
|
49
|
+
baseURL?: string;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
type PluginMcp = PluginFactoryOptions<'plugin-mcp', Options, ResolvedOptions, never, ResolvePathOptions>;
|
|
53
|
+
|
|
54
|
+
export type { Options as O, PluginMcp as P };
|
package/package.json
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kubb/plugin-mcp",
|
|
3
|
+
"version": "0.0.0-canary-20250414193247",
|
|
4
|
+
"description": "Generator mcp",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"typescript",
|
|
7
|
+
"plugins",
|
|
8
|
+
"kubb",
|
|
9
|
+
"codegen",
|
|
10
|
+
"mcp",
|
|
11
|
+
"ai",
|
|
12
|
+
"claude",
|
|
13
|
+
"openapi"
|
|
14
|
+
],
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/kubb-labs/kubb.git",
|
|
18
|
+
"directory": "packages/plugin-mcp"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"author": "stijnvanhulle",
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"type": "module",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"import": "./dist/index.js",
|
|
27
|
+
"require": "./dist/index.cjs",
|
|
28
|
+
"default": "./dist/index.cjs"
|
|
29
|
+
},
|
|
30
|
+
"./utils": {
|
|
31
|
+
"import": "./dist/utils.js",
|
|
32
|
+
"require": "./dist/utils.cjs",
|
|
33
|
+
"default": "./dist/utils.cjs"
|
|
34
|
+
},
|
|
35
|
+
"./hooks": {
|
|
36
|
+
"import": "./dist/hooks.js",
|
|
37
|
+
"require": "./dist/hooks.cjs",
|
|
38
|
+
"default": "./dist/hooks.cjs"
|
|
39
|
+
},
|
|
40
|
+
"./components": {
|
|
41
|
+
"import": "./dist/components.js",
|
|
42
|
+
"require": "./dist/components.cjs",
|
|
43
|
+
"default": "./dist/components.cjs"
|
|
44
|
+
},
|
|
45
|
+
"./generators": {
|
|
46
|
+
"import": "./dist/generators.js",
|
|
47
|
+
"require": "./dist/generators.cjs",
|
|
48
|
+
"default": "./dist/generators.cjs"
|
|
49
|
+
},
|
|
50
|
+
"./package.json": "./package.json",
|
|
51
|
+
"./*": "./*"
|
|
52
|
+
},
|
|
53
|
+
"main": "dist/index.cjs",
|
|
54
|
+
"module": "dist/index.js",
|
|
55
|
+
"types": "./dist/index.d.ts",
|
|
56
|
+
"typesVersions": {
|
|
57
|
+
"*": {
|
|
58
|
+
"utils": [
|
|
59
|
+
"./dist/utils.d.ts"
|
|
60
|
+
],
|
|
61
|
+
"hooks": [
|
|
62
|
+
"./dist/hooks.d.ts"
|
|
63
|
+
],
|
|
64
|
+
"components": [
|
|
65
|
+
"./dist/components.d.ts"
|
|
66
|
+
],
|
|
67
|
+
"generators": [
|
|
68
|
+
"./dist/generators.d.ts"
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"files": [
|
|
73
|
+
"src",
|
|
74
|
+
"dist",
|
|
75
|
+
"!/**/**.test.**",
|
|
76
|
+
"!/**/__tests__/**"
|
|
77
|
+
],
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"@kubb/fs": "0.0.0-canary-20250414193247",
|
|
80
|
+
"@kubb/core": "0.0.0-canary-20250414193247",
|
|
81
|
+
"@kubb/oas": "0.0.0-canary-20250414193247",
|
|
82
|
+
"@kubb/plugin-client": "0.0.0-canary-20250414193247",
|
|
83
|
+
"@kubb/plugin-oas": "0.0.0-canary-20250414193247",
|
|
84
|
+
"@kubb/plugin-ts": "0.0.0-canary-20250414193247",
|
|
85
|
+
"@kubb/react": "0.0.0-canary-20250414193247",
|
|
86
|
+
"@kubb/plugin-zod": "0.0.0-canary-20250414193247"
|
|
87
|
+
},
|
|
88
|
+
"devDependencies": {
|
|
89
|
+
"@types/react": "^18.3.20",
|
|
90
|
+
"react": "^18.3.1",
|
|
91
|
+
"tsup": "^8.4.0",
|
|
92
|
+
"typescript": "^5.8.3",
|
|
93
|
+
"@kubb/config-ts": "0.0.0-canary-20250414193247",
|
|
94
|
+
"@kubb/config-tsup": "0.0.0-canary-20250414193247"
|
|
95
|
+
},
|
|
96
|
+
"peerDependencies": {
|
|
97
|
+
"@kubb/react": "0.0.0-canary-20250414193247"
|
|
98
|
+
},
|
|
99
|
+
"engines": {
|
|
100
|
+
"node": ">=20"
|
|
101
|
+
},
|
|
102
|
+
"publishConfig": {
|
|
103
|
+
"access": "public",
|
|
104
|
+
"registry": "https://registry.npmjs.org/"
|
|
105
|
+
},
|
|
106
|
+
"scripts": {
|
|
107
|
+
"build": "tsup",
|
|
108
|
+
"clean": "npx rimraf ./dist",
|
|
109
|
+
"lint": "bun biome lint .",
|
|
110
|
+
"lint:fix": "bun biome lint --apply-unsafe .",
|
|
111
|
+
"release": "pnpm publish --no-git-check",
|
|
112
|
+
"release:canary": "bash ../../.github/canary.sh && node ../../scripts/build.js canary && pnpm publish --no-git-check",
|
|
113
|
+
"start": "tsup --watch",
|
|
114
|
+
"test": "vitest --passWithNoTests",
|
|
115
|
+
"typecheck": "tsc -p ./tsconfig.json --noEmit --emitDeclarationOnly false"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import type * as KubbFile from '@kubb/fs/types'
|
|
2
|
+
|
|
3
|
+
import { Const, File, FunctionParams } from '@kubb/react'
|
|
4
|
+
import type { OperationSchemas } from '@kubb/plugin-oas'
|
|
5
|
+
import { getPathParams, isOptional } from '@kubb/plugin-oas/utils'
|
|
6
|
+
import { isNullable, isReference } from '@kubb/oas'
|
|
7
|
+
import { camelCase } from '@kubb/core/transformers'
|
|
8
|
+
|
|
9
|
+
type Props = {
|
|
10
|
+
name: string
|
|
11
|
+
serverName: string
|
|
12
|
+
serverVersion: string
|
|
13
|
+
operations: Array<{
|
|
14
|
+
operationId: string
|
|
15
|
+
description?: string
|
|
16
|
+
mcp: {
|
|
17
|
+
name: string
|
|
18
|
+
file: KubbFile.File
|
|
19
|
+
}
|
|
20
|
+
zod: {
|
|
21
|
+
name: string
|
|
22
|
+
file: KubbFile.File
|
|
23
|
+
schemas: OperationSchemas
|
|
24
|
+
}
|
|
25
|
+
type: {
|
|
26
|
+
schemas: OperationSchemas
|
|
27
|
+
}
|
|
28
|
+
}>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type GetParamsProps = {
|
|
32
|
+
schemas: OperationSchemas
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getParams({ schemas }: GetParamsProps) {
|
|
36
|
+
const pathParams = getPathParams(schemas.pathParams, {
|
|
37
|
+
typed: false,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
return FunctionParams.factory({
|
|
41
|
+
data: {
|
|
42
|
+
mode: 'object',
|
|
43
|
+
children: {
|
|
44
|
+
...Object.entries(pathParams).reduce((acc, [key, param]) => {
|
|
45
|
+
if (param && schemas.pathParams?.name) {
|
|
46
|
+
let suffix = '.shape'
|
|
47
|
+
|
|
48
|
+
if (isNullable(schemas.pathParams.schema)) {
|
|
49
|
+
if (isReference(schemas.pathParams)) {
|
|
50
|
+
suffix = '.unwrap().schema.unwrap().shape'
|
|
51
|
+
} else {
|
|
52
|
+
suffix = '.unwrap().shape'
|
|
53
|
+
}
|
|
54
|
+
} else {
|
|
55
|
+
if (isReference(schemas.pathParams)) {
|
|
56
|
+
suffix = '.schema.shape'
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
param.value = `${schemas.pathParams?.name}${suffix}['${key}']`
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
...acc,
|
|
65
|
+
[camelCase(key)]: param,
|
|
66
|
+
}
|
|
67
|
+
}, {}),
|
|
68
|
+
data: schemas.request?.name
|
|
69
|
+
? {
|
|
70
|
+
value: schemas.request?.name,
|
|
71
|
+
optional: isOptional(schemas.request?.schema),
|
|
72
|
+
}
|
|
73
|
+
: undefined,
|
|
74
|
+
params: schemas.queryParams?.name
|
|
75
|
+
? {
|
|
76
|
+
value: schemas.queryParams?.name,
|
|
77
|
+
optional: isOptional(schemas.queryParams?.schema),
|
|
78
|
+
}
|
|
79
|
+
: undefined,
|
|
80
|
+
headers: schemas.headerParams?.name
|
|
81
|
+
? {
|
|
82
|
+
value: schemas.headerParams?.name,
|
|
83
|
+
optional: isOptional(schemas.headerParams?.schema),
|
|
84
|
+
}
|
|
85
|
+
: undefined,
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function Server({ name, serverName, serverVersion, operations }: Props) {
|
|
92
|
+
return (
|
|
93
|
+
<>
|
|
94
|
+
<File.Source name={name} isExportable isIndexable>
|
|
95
|
+
<Const name={'server'} export>
|
|
96
|
+
{`
|
|
97
|
+
new McpServer({
|
|
98
|
+
name: '${serverName}',
|
|
99
|
+
version: '${serverVersion}',
|
|
100
|
+
})
|
|
101
|
+
`}
|
|
102
|
+
</Const>
|
|
103
|
+
|
|
104
|
+
{operations
|
|
105
|
+
.map(({ operationId, mcp, zod, description = '' }) => {
|
|
106
|
+
const paramsClient = getParams({ schemas: zod.schemas })
|
|
107
|
+
|
|
108
|
+
if (zod.schemas.request?.name || zod.schemas.headerParams?.name || zod.schemas.queryParams?.name || zod.schemas.pathParams?.name) {
|
|
109
|
+
return `
|
|
110
|
+
server.tool('${operationId}', '${description}', ${paramsClient.toObjectValue()}, async (${paramsClient.toObject()}) => {
|
|
111
|
+
return ${mcp.name}(${paramsClient.toObject()})
|
|
112
|
+
})
|
|
113
|
+
`
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return `
|
|
117
|
+
server.tool('${operationId}', '${description}', async () => {
|
|
118
|
+
return ${mcp.name}(${paramsClient.toObject()})
|
|
119
|
+
})
|
|
120
|
+
`
|
|
121
|
+
})
|
|
122
|
+
.filter(Boolean)}
|
|
123
|
+
|
|
124
|
+
{`
|
|
125
|
+
async function startServer() {
|
|
126
|
+
try {
|
|
127
|
+
const transport = new StdioServerTransport()
|
|
128
|
+
await server.connect(transport)
|
|
129
|
+
console.error('Server started and listening on stdio')
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error('Failed to start server:', error)
|
|
132
|
+
process.exit(1)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
startServer()
|
|
137
|
+
`}
|
|
138
|
+
</File.Source>
|
|
139
|
+
</>
|
|
140
|
+
)
|
|
141
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Server } from './Server.tsx'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import client from '@kubb/plugin-client/clients/axios'
|
|
2
|
+
import type { ResponseErrorConfig } from '@kubb/plugin-client/clients/axios'
|
|
3
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @summary Create a pet
|
|
7
|
+
* {@link /pets}
|
|
8
|
+
*/
|
|
9
|
+
export async function createPetsHandler({ data }: { data: CreatePetsMutationRequest }): Promise<Promise<CallToolResult>> {
|
|
10
|
+
const res = await client<CreatePetsMutationResponse, ResponseErrorConfig<Error>, CreatePetsMutationRequest>({ method: 'POST', url: `/pets`, data })
|
|
11
|
+
return {
|
|
12
|
+
content: [
|
|
13
|
+
{
|
|
14
|
+
type: 'text',
|
|
15
|
+
text: JSON.stringify(res.data),
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import client from '@kubb/plugin-client/clients/axios'
|
|
2
|
+
import type { ResponseErrorConfig } from '@kubb/plugin-client/clients/axios'
|
|
3
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* {@link /pets/:petId}
|
|
7
|
+
*/
|
|
8
|
+
export async function deletePetsPetidHandler(): Promise<Promise<CallToolResult>> {
|
|
9
|
+
const res = await client<DeletePetsPetidMutationResponse, ResponseErrorConfig<Error>, unknown>({ method: 'DELETE', url: `/pets/${petId}` })
|
|
10
|
+
return {
|
|
11
|
+
content: [
|
|
12
|
+
{
|
|
13
|
+
type: 'text',
|
|
14
|
+
text: JSON.stringify(res.data),
|
|
15
|
+
},
|
|
16
|
+
],
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import client from '@kubb/plugin-client/clients/axios'
|
|
2
|
+
import type { ResponseErrorConfig } from '@kubb/plugin-client/clients/axios'
|
|
3
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @summary List all pets
|
|
7
|
+
* {@link /pets}
|
|
8
|
+
*/
|
|
9
|
+
export async function listPetsHandler({ params }: { params?: ListPetsQueryParams }): Promise<Promise<CallToolResult>> {
|
|
10
|
+
const res = await client<ListPetsQueryResponse, ResponseErrorConfig<Error>, unknown>({ method: 'GET', url: `/pets`, params })
|
|
11
|
+
return {
|
|
12
|
+
content: [
|
|
13
|
+
{
|
|
14
|
+
type: 'text',
|
|
15
|
+
text: JSON.stringify(res.data),
|
|
16
|
+
},
|
|
17
|
+
],
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated by Kubb (https://kubb.dev/).
|
|
3
|
+
* Do not edit manually.
|
|
4
|
+
*/
|
|
5
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio'
|
|
7
|
+
import { listPetsHandler, listPetsQueryParams, createPetsHandler, createPetsMutationRequest, showPetByIdHandler, showPetByIdPathParams } from './showPetById'
|
|
8
|
+
|
|
9
|
+
export const server = new McpServer({
|
|
10
|
+
name: 'Swagger Petstore',
|
|
11
|
+
version: '3.0.0',
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
server.tool('listPets', '', { params: listPetsQueryParams }, async ({ params }) => {
|
|
15
|
+
return listPetsHandler({ params })
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
server.tool('createPets', '', { data: createPetsMutationRequest }, async ({ data }) => {
|
|
19
|
+
return createPetsHandler({ data })
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
server.tool('showPetById', '', { petId: showPetByIdPathParams.shape['petId'], testId: showPetByIdPathParams.shape['testId'] }, async ({ petId, testId }) => {
|
|
23
|
+
return showPetByIdHandler({ petId, testId })
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
async function startServer() {
|
|
27
|
+
try {
|
|
28
|
+
const transport = new StdioServerTransport()
|
|
29
|
+
await server.connect(transport)
|
|
30
|
+
console.error('Server started and listening on stdio')
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error('Failed to start server:', error)
|
|
33
|
+
process.exit(1)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
startServer()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import client from '@kubb/plugin-client/clients/axios'
|
|
2
|
+
import type { ResponseErrorConfig } from '@kubb/plugin-client/clients/axios'
|
|
3
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @summary Info for a specific pet
|
|
7
|
+
* {@link /pets/:petId}
|
|
8
|
+
*/
|
|
9
|
+
export async function showPetByIdHandler({
|
|
10
|
+
petId,
|
|
11
|
+
testId,
|
|
12
|
+
}: {
|
|
13
|
+
petId: ShowPetByIdPathParams['petId']
|
|
14
|
+
testId: ShowPetByIdPathParams['testId']
|
|
15
|
+
}): Promise<Promise<CallToolResult>> {
|
|
16
|
+
const res = await client<ShowPetByIdQueryResponse, ResponseErrorConfig<Error>, unknown>({ method: 'GET', url: `/pets/${petId}` })
|
|
17
|
+
return {
|
|
18
|
+
content: [
|
|
19
|
+
{
|
|
20
|
+
type: 'text',
|
|
21
|
+
text: JSON.stringify(res.data),
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { createReactGenerator } from '@kubb/plugin-oas'
|
|
2
|
+
import { useOas, useOperationManager } from '@kubb/plugin-oas/hooks'
|
|
3
|
+
import { getBanner, getFooter } from '@kubb/plugin-oas/utils'
|
|
4
|
+
import { pluginTsName } from '@kubb/plugin-ts'
|
|
5
|
+
import { File, useApp } from '@kubb/react'
|
|
6
|
+
import type { PluginMcp } from '../types'
|
|
7
|
+
import { Client } from '@kubb/plugin-client/components'
|
|
8
|
+
|
|
9
|
+
export const mcpGenerator = createReactGenerator<PluginMcp>({
|
|
10
|
+
name: 'mcp',
|
|
11
|
+
Operation({ operation }) {
|
|
12
|
+
const {
|
|
13
|
+
plugin: { options },
|
|
14
|
+
} = useApp<PluginMcp>()
|
|
15
|
+
const oas = useOas()
|
|
16
|
+
const { getSchemas, getName, getFile } = useOperationManager()
|
|
17
|
+
|
|
18
|
+
const mcp = {
|
|
19
|
+
name: getName(operation, { type: 'function', suffix: 'handler' }),
|
|
20
|
+
file: getFile(operation),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const type = {
|
|
24
|
+
file: getFile(operation, { pluginKey: [pluginTsName] }),
|
|
25
|
+
schemas: getSchemas(operation, { pluginKey: [pluginTsName], type: 'type' }),
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<File
|
|
30
|
+
baseName={mcp.file.baseName}
|
|
31
|
+
path={mcp.file.path}
|
|
32
|
+
meta={mcp.file.meta}
|
|
33
|
+
banner={getBanner({ oas, output: options.output })}
|
|
34
|
+
footer={getFooter({ oas, output: options.output })}
|
|
35
|
+
>
|
|
36
|
+
<File.Import name={['CallToolResult']} path={'@modelcontextprotocol/sdk/types'} isTypeOnly />
|
|
37
|
+
<File.Import name={'client'} path={options.client.importPath} />
|
|
38
|
+
<File.Import name={['RequestConfig', 'ResponseErrorConfig']} path={options.client.importPath} isTypeOnly />
|
|
39
|
+
<File.Import
|
|
40
|
+
name={[
|
|
41
|
+
type.schemas.request?.name,
|
|
42
|
+
type.schemas.response.name,
|
|
43
|
+
type.schemas.pathParams?.name,
|
|
44
|
+
type.schemas.queryParams?.name,
|
|
45
|
+
type.schemas.headerParams?.name,
|
|
46
|
+
...(type.schemas.statusCodes?.map((item) => item.name) || []),
|
|
47
|
+
].filter(Boolean)}
|
|
48
|
+
root={mcp.file.path}
|
|
49
|
+
path={type.file.path}
|
|
50
|
+
isTypeOnly
|
|
51
|
+
/>
|
|
52
|
+
|
|
53
|
+
<Client
|
|
54
|
+
name={mcp.name}
|
|
55
|
+
isConfigurable={false}
|
|
56
|
+
returnType={'Promise<CallToolResult>'}
|
|
57
|
+
baseURL={options.client.baseURL}
|
|
58
|
+
operation={operation}
|
|
59
|
+
typeSchemas={type.schemas}
|
|
60
|
+
zodSchemas={undefined}
|
|
61
|
+
dataReturnType={options.client.dataReturnType}
|
|
62
|
+
paramsType={'object'}
|
|
63
|
+
paramsCasing={'camelcase'}
|
|
64
|
+
pathParamsType={'object'}
|
|
65
|
+
parser={'client'}
|
|
66
|
+
>
|
|
67
|
+
{options.client.dataReturnType === 'data' &&
|
|
68
|
+
`return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: 'text',
|
|
72
|
+
text: JSON.stringify(res.data)
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
}`}
|
|
76
|
+
{options.client.dataReturnType === 'full' &&
|
|
77
|
+
`return {
|
|
78
|
+
content: [
|
|
79
|
+
{
|
|
80
|
+
type: 'text',
|
|
81
|
+
text: JSON.stringify(res)
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}`}
|
|
85
|
+
</Client>
|
|
86
|
+
</File>
|
|
87
|
+
)
|
|
88
|
+
},
|
|
89
|
+
})
|