@tanstack/cta-cli 0.10.0-alpha.19 → 0.10.0-alpha.21

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/mcp.ts ADDED
@@ -0,0 +1,247 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
+ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
4
+ import express from 'express'
5
+ import { z } from 'zod'
6
+
7
+ import {
8
+ createApp,
9
+ createDefaultEnvironment,
10
+ finalizeAddOns,
11
+ getFrameworkById,
12
+ } from '@tanstack/cta-engine'
13
+
14
+ import type { Mode } from '@tanstack/cta-engine'
15
+
16
+ function createServer({
17
+ appName,
18
+ forcedAddOns = [],
19
+ }: {
20
+ appName?: string
21
+ forcedAddOns?: Array<string>
22
+ name?: string
23
+ }) {
24
+ const server = new McpServer({
25
+ name: `${appName} Application Builder`,
26
+ version: '1.0.0',
27
+ })
28
+
29
+ server.tool(
30
+ 'listTanStackReactAddOns',
31
+ 'List the available add-ons for creating TanStack React applications',
32
+ {},
33
+ () => {
34
+ const framework = getFrameworkById('react-cra')!
35
+ return {
36
+ content: [
37
+ {
38
+ type: 'text',
39
+ text: JSON.stringify(
40
+ framework
41
+ .getAddOns()
42
+ .filter((addOn) => addOn.modes.includes('file-router'))
43
+ .map((addOn) => ({
44
+ id: addOn.id,
45
+ description: addOn.description,
46
+ })),
47
+ ),
48
+ },
49
+ ],
50
+ }
51
+ },
52
+ )
53
+
54
+ server.tool(
55
+ 'createTanStackReactApplication',
56
+ 'Create a new TanStack React application',
57
+ {
58
+ projectName: z
59
+ .string()
60
+ .describe(
61
+ 'The package.json module name of the application (will also be the directory name)',
62
+ ),
63
+ cwd: z.string().describe('The directory to create the application in'),
64
+ addOns: z.array(z.string()).describe('The IDs of the add-ons to install'),
65
+ targetDir: z
66
+ .string()
67
+ .describe(
68
+ 'The directory to create the application in. Use the absolute path of the directory you want the application to be created in',
69
+ ),
70
+ },
71
+ async ({ projectName, addOns, cwd, targetDir }) => {
72
+ const framework = getFrameworkById('react-cra')!
73
+ try {
74
+ process.chdir(cwd)
75
+ try {
76
+ const chosenAddOns = await finalizeAddOns(
77
+ framework,
78
+ 'file-router',
79
+ Array.from(
80
+ new Set([
81
+ ...(addOns as unknown as Array<string>),
82
+ ...forcedAddOns,
83
+ ]),
84
+ ),
85
+ )
86
+ await createApp(createDefaultEnvironment(), {
87
+ projectName: projectName.replace(/^\//, './'),
88
+ targetDir,
89
+ framework,
90
+ typescript: true,
91
+ tailwind: true,
92
+ packageManager: 'pnpm',
93
+ mode: 'file-router',
94
+ chosenAddOns,
95
+ git: true,
96
+ })
97
+ } catch (error) {
98
+ console.error(error)
99
+ return {
100
+ content: [
101
+ { type: 'text', text: `Error creating application: ${error}` },
102
+ ],
103
+ }
104
+ }
105
+ return {
106
+ content: [{ type: 'text', text: 'Application created successfully' }],
107
+ }
108
+ } catch (error) {
109
+ return {
110
+ content: [
111
+ { type: 'text', text: `Error creating application: ${error}` },
112
+ ],
113
+ }
114
+ }
115
+ },
116
+ )
117
+
118
+ server.tool(
119
+ 'listTanStackSolidAddOns',
120
+ 'List the available add-ons for creating TanStack Solid applications',
121
+ {},
122
+ () => {
123
+ const framework = getFrameworkById('solid')!
124
+ return {
125
+ content: [
126
+ {
127
+ type: 'text',
128
+ text: JSON.stringify(
129
+ framework
130
+ .getAddOns()
131
+ .filter((addOn) => addOn.modes.includes('file-router'))
132
+ .map((addOn) => ({
133
+ id: addOn.id,
134
+ description: addOn.description,
135
+ })),
136
+ ),
137
+ },
138
+ ],
139
+ }
140
+ },
141
+ )
142
+
143
+ server.tool(
144
+ 'createTanStackSolidApplication',
145
+ 'Create a new TanStack Solid application',
146
+ {
147
+ projectName: z
148
+ .string()
149
+ .describe(
150
+ 'The package.json module name of the application (will also be the directory name)',
151
+ ),
152
+ cwd: z.string().describe('The directory to create the application in'),
153
+ addOns: z.array(z.string()).describe('The IDs of the add-ons to install'),
154
+ targetDir: z
155
+ .string()
156
+ .describe(
157
+ 'The directory to create the application in. Use the absolute path of the directory you want the application to be created in',
158
+ ),
159
+ },
160
+ async ({ projectName, addOns, cwd, targetDir }) => {
161
+ const framework = getFrameworkById('solid')!
162
+ try {
163
+ process.chdir(cwd)
164
+ try {
165
+ const chosenAddOns = await finalizeAddOns(
166
+ framework,
167
+ 'file-router',
168
+ Array.from(
169
+ new Set([
170
+ ...(addOns as unknown as Array<string>),
171
+ ...forcedAddOns,
172
+ ]),
173
+ ),
174
+ )
175
+ await createApp(createDefaultEnvironment(), {
176
+ projectName: projectName.replace(/^\//, './'),
177
+ targetDir,
178
+ framework,
179
+ typescript: true,
180
+ tailwind: true,
181
+ packageManager: 'pnpm',
182
+ mode: 'file-router',
183
+ chosenAddOns,
184
+ git: true,
185
+ })
186
+ } catch (error) {
187
+ return {
188
+ content: [
189
+ { type: 'text', text: `Error creating application: ${error}` },
190
+ ],
191
+ }
192
+ }
193
+ return {
194
+ content: [{ type: 'text', text: 'Application created successfully' }],
195
+ }
196
+ } catch (error) {
197
+ return {
198
+ content: [
199
+ { type: 'text', text: `Error creating application: ${error}` },
200
+ ],
201
+ }
202
+ }
203
+ },
204
+ )
205
+
206
+ return server
207
+ }
208
+
209
+ export async function runMCPServer(
210
+ sse: boolean,
211
+ {
212
+ forcedAddOns,
213
+ appName,
214
+ name,
215
+ }: {
216
+ forcedMode?: Mode
217
+ forcedAddOns?: Array<string>
218
+ appName?: string
219
+ name?: string
220
+ },
221
+ ) {
222
+ let transport: SSEServerTransport | null = null
223
+
224
+ const server = createServer({ appName, forcedAddOns, name })
225
+ if (sse) {
226
+ const app = express()
227
+
228
+ app.get('/sse', (req, res) => {
229
+ transport = new SSEServerTransport('/messages', res)
230
+ server.connect(transport)
231
+ })
232
+
233
+ app.post('/messages', (req, res) => {
234
+ if (transport) {
235
+ transport.handlePostMessage(req, res)
236
+ }
237
+ })
238
+
239
+ const port = process.env.PORT || 8080
240
+ app.listen(port, () => {
241
+ console.log(`Server is running on port http://localhost:${port}/sse`)
242
+ })
243
+ } else {
244
+ const transport = new StdioServerTransport()
245
+ await server.connect(transport)
246
+ }
247
+ }