@tanstack/cli 0.0.7 → 0.48.2
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/dist/bin.js +7 -0
- package/dist/cli.js +481 -0
- package/dist/command-line.js +174 -0
- package/dist/dev-watch.js +290 -0
- package/dist/file-syncer.js +148 -0
- package/dist/index.js +1 -0
- package/dist/mcp/api.js +31 -0
- package/dist/mcp/tools.js +250 -0
- package/dist/mcp/types.js +37 -0
- package/dist/mcp.js +121 -0
- package/dist/options.js +162 -0
- package/dist/types/bin.d.ts +2 -0
- package/dist/types/cli.d.ts +16 -0
- package/dist/types/command-line.d.ts +10 -0
- package/dist/types/dev-watch.d.ts +27 -0
- package/dist/types/file-syncer.d.ts +18 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/mcp/api.d.ts +4 -0
- package/dist/types/mcp/tools.d.ts +2 -0
- package/dist/types/mcp/types.d.ts +217 -0
- package/dist/types/mcp.d.ts +6 -0
- package/dist/types/options.d.ts +8 -0
- package/dist/types/types.d.ts +25 -0
- package/dist/types/ui-environment.d.ts +2 -0
- package/dist/types/ui-prompts.d.ts +12 -0
- package/dist/types/utils.d.ts +8 -0
- package/dist/types.js +1 -0
- package/dist/ui-environment.js +52 -0
- package/dist/ui-prompts.js +244 -0
- package/dist/utils.js +30 -0
- package/package.json +46 -46
- package/src/bin.ts +6 -93
- package/src/cli.ts +692 -0
- package/src/command-line.ts +236 -0
- package/src/dev-watch.ts +430 -0
- package/src/file-syncer.ts +205 -0
- package/src/index.ts +1 -85
- package/src/mcp.ts +190 -0
- package/src/options.ts +260 -0
- package/src/types.ts +27 -0
- package/src/ui-environment.ts +74 -0
- package/src/ui-prompts.ts +322 -0
- package/src/utils.ts +38 -0
- package/tests/command-line.test.ts +304 -0
- package/tests/index.test.ts +9 -0
- package/tests/mcp.test.ts +225 -0
- package/tests/options.test.ts +304 -0
- package/tests/setupVitest.ts +6 -0
- package/tests/ui-environment.test.ts +97 -0
- package/tests/ui-prompts.test.ts +238 -0
- package/tsconfig.json +17 -0
- package/vitest.config.js +7 -0
- package/dist/bin.cjs +0 -761
- package/dist/bin.d.cts +0 -1
- package/dist/bin.d.mts +0 -1
- package/dist/bin.mjs +0 -760
- package/dist/index.cjs +0 -36
- package/dist/index.d.cts +0 -1172
- package/dist/index.d.mts +0 -1172
- package/dist/index.mjs +0 -3
- package/dist/template-CkAkdP8n.mjs +0 -2545
- package/dist/template-Cup47s9h.cjs +0 -2783
- package/src/api/fetch.test.ts +0 -114
- package/src/api/fetch.ts +0 -249
- package/src/cache/index.ts +0 -89
- package/src/commands/create.ts +0 -463
- package/src/commands/mcp.test.ts +0 -152
- package/src/commands/mcp.ts +0 -203
- package/src/engine/compile-with-addons.test.ts +0 -302
- package/src/engine/compile.test.ts +0 -404
- package/src/engine/compile.ts +0 -551
- package/src/engine/config-file.test.ts +0 -118
- package/src/engine/config-file.ts +0 -61
- package/src/engine/custom-addons/integration.ts +0 -323
- package/src/engine/custom-addons/shared.test.ts +0 -98
- package/src/engine/custom-addons/shared.ts +0 -281
- package/src/engine/custom-addons/template.test.ts +0 -288
- package/src/engine/custom-addons/template.ts +0 -124
- package/src/engine/template.test.ts +0 -256
- package/src/engine/template.ts +0 -269
- package/src/engine/types.ts +0 -336
- package/src/parse-gitignore.d.ts +0 -5
- package/src/templates/base.ts +0 -891
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import crypto from 'node:crypto'
|
|
4
|
+
import * as diff from 'diff'
|
|
5
|
+
|
|
6
|
+
export interface FileUpdate {
|
|
7
|
+
path: string
|
|
8
|
+
diff?: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface SyncResult {
|
|
12
|
+
updated: Array<FileUpdate>
|
|
13
|
+
skipped: Array<string>
|
|
14
|
+
created: Array<string>
|
|
15
|
+
errors: Array<string>
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class FileSyncer {
|
|
19
|
+
async sync(sourceDir: string, targetDir: string): Promise<SyncResult> {
|
|
20
|
+
const result: SyncResult = {
|
|
21
|
+
updated: [],
|
|
22
|
+
skipped: [],
|
|
23
|
+
created: [],
|
|
24
|
+
errors: [],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Ensure directories exist
|
|
28
|
+
if (!fs.existsSync(sourceDir)) {
|
|
29
|
+
throw new Error(`Source directory does not exist: ${sourceDir}`)
|
|
30
|
+
}
|
|
31
|
+
if (!fs.existsSync(targetDir)) {
|
|
32
|
+
throw new Error(`Target directory does not exist: ${targetDir}`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Walk through source directory and sync files
|
|
36
|
+
await this.syncDirectory(sourceDir, targetDir, sourceDir, result)
|
|
37
|
+
|
|
38
|
+
return result
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private async syncDirectory(
|
|
42
|
+
currentPath: string,
|
|
43
|
+
targetBase: string,
|
|
44
|
+
sourceBase: string,
|
|
45
|
+
result: SyncResult,
|
|
46
|
+
): Promise<void> {
|
|
47
|
+
const entries = await fs.promises.readdir(currentPath, {
|
|
48
|
+
withFileTypes: true,
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const sourcePath = path.join(currentPath, entry.name)
|
|
53
|
+
const relativePath = path.relative(sourceBase, sourcePath)
|
|
54
|
+
const targetPath = path.join(targetBase, relativePath)
|
|
55
|
+
|
|
56
|
+
// Skip certain directories
|
|
57
|
+
if (entry.isDirectory()) {
|
|
58
|
+
if (this.shouldSkipDirectory(entry.name)) {
|
|
59
|
+
continue
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Ensure target directory exists
|
|
63
|
+
if (!fs.existsSync(targetPath)) {
|
|
64
|
+
await fs.promises.mkdir(targetPath, { recursive: true })
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Recursively sync subdirectory
|
|
68
|
+
await this.syncDirectory(sourcePath, targetBase, sourceBase, result)
|
|
69
|
+
} else if (entry.isFile()) {
|
|
70
|
+
// Skip certain files
|
|
71
|
+
if (this.shouldSkipFile(entry.name)) {
|
|
72
|
+
continue
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const shouldUpdate = await this.shouldUpdateFile(
|
|
77
|
+
sourcePath,
|
|
78
|
+
targetPath,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if (shouldUpdate) {
|
|
82
|
+
// Check if file exists to generate diff
|
|
83
|
+
let fileDiff: string | undefined
|
|
84
|
+
const targetExists = fs.existsSync(targetPath)
|
|
85
|
+
|
|
86
|
+
if (targetExists) {
|
|
87
|
+
// Generate diff for existing files
|
|
88
|
+
const oldContent = await fs.promises.readFile(targetPath, 'utf-8')
|
|
89
|
+
const newContent = await fs.promises.readFile(sourcePath, 'utf-8')
|
|
90
|
+
|
|
91
|
+
const changes = diff.createPatch(
|
|
92
|
+
relativePath,
|
|
93
|
+
oldContent,
|
|
94
|
+
newContent,
|
|
95
|
+
'Previous',
|
|
96
|
+
'Current',
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
// Only include diff if there are actual changes
|
|
100
|
+
if (changes && changes.split('\n').length > 5) {
|
|
101
|
+
fileDiff = changes
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Copy file
|
|
106
|
+
await fs.promises.copyFile(sourcePath, targetPath)
|
|
107
|
+
|
|
108
|
+
// Touch file to trigger dev server reload
|
|
109
|
+
const now = new Date()
|
|
110
|
+
await fs.promises.utimes(targetPath, now, now)
|
|
111
|
+
|
|
112
|
+
if (!targetExists) {
|
|
113
|
+
result.created.push(relativePath)
|
|
114
|
+
} else {
|
|
115
|
+
result.updated.push({
|
|
116
|
+
path: relativePath,
|
|
117
|
+
diff: fileDiff,
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
} else {
|
|
121
|
+
result.skipped.push(relativePath)
|
|
122
|
+
}
|
|
123
|
+
} catch (error) {
|
|
124
|
+
result.errors.push(
|
|
125
|
+
`${relativePath}: ${error instanceof Error ? error.message : String(error)}`,
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private async shouldUpdateFile(
|
|
133
|
+
sourcePath: string,
|
|
134
|
+
targetPath: string,
|
|
135
|
+
): Promise<boolean> {
|
|
136
|
+
// If target doesn't exist, definitely update
|
|
137
|
+
if (!fs.existsSync(targetPath)) {
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Compare file sizes first (quick check)
|
|
142
|
+
const [sourceStats, targetStats] = await Promise.all([
|
|
143
|
+
fs.promises.stat(sourcePath),
|
|
144
|
+
fs.promises.stat(targetPath),
|
|
145
|
+
])
|
|
146
|
+
|
|
147
|
+
if (sourceStats.size !== targetStats.size) {
|
|
148
|
+
return true
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Compare MD5 hashes for content
|
|
152
|
+
const [sourceHash, targetHash] = await Promise.all([
|
|
153
|
+
this.calculateHash(sourcePath),
|
|
154
|
+
this.calculateHash(targetPath),
|
|
155
|
+
])
|
|
156
|
+
|
|
157
|
+
return sourceHash !== targetHash
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private async calculateHash(filePath: string): Promise<string> {
|
|
161
|
+
return new Promise((resolve, reject) => {
|
|
162
|
+
const hash = crypto.createHash('md5')
|
|
163
|
+
const stream = fs.createReadStream(filePath)
|
|
164
|
+
|
|
165
|
+
stream.on('data', (data) => hash.update(data))
|
|
166
|
+
stream.on('end', () => resolve(hash.digest('hex')))
|
|
167
|
+
stream.on('error', reject)
|
|
168
|
+
})
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
private shouldSkipDirectory(name: string): boolean {
|
|
172
|
+
const skipDirs = [
|
|
173
|
+
'node_modules',
|
|
174
|
+
'.git',
|
|
175
|
+
'dist',
|
|
176
|
+
'build',
|
|
177
|
+
'.next',
|
|
178
|
+
'.nuxt',
|
|
179
|
+
'.cache',
|
|
180
|
+
'.tmp-dev',
|
|
181
|
+
'coverage',
|
|
182
|
+
'.turbo',
|
|
183
|
+
]
|
|
184
|
+
|
|
185
|
+
return skipDirs.includes(name) || name.startsWith('.')
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private shouldSkipFile(name: string): boolean {
|
|
189
|
+
const skipFiles = [
|
|
190
|
+
'.DS_Store',
|
|
191
|
+
'Thumbs.db',
|
|
192
|
+
'desktop.ini',
|
|
193
|
+
'.cta.json', // Skip .cta.json as it contains framework ID that changes each build
|
|
194
|
+
]
|
|
195
|
+
|
|
196
|
+
const skipExtensions = ['.log', '.lock', '.pid', '.seed', '.sqlite']
|
|
197
|
+
|
|
198
|
+
if (skipFiles.includes(name)) {
|
|
199
|
+
return true
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const ext = path.extname(name).toLowerCase()
|
|
203
|
+
return skipExtensions.includes(ext)
|
|
204
|
+
}
|
|
205
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,85 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { compile, compileWithAttribution } from './engine/compile.js'
|
|
3
|
-
export { processTemplateFile, relativePath } from './engine/template.js'
|
|
4
|
-
|
|
5
|
-
// Config file exports
|
|
6
|
-
export {
|
|
7
|
-
CONFIG_FILE,
|
|
8
|
-
writeConfigFile,
|
|
9
|
-
readConfigFile,
|
|
10
|
-
} from './engine/config-file.js'
|
|
11
|
-
export type { PersistedOptions } from './engine/config-file.js'
|
|
12
|
-
|
|
13
|
-
// Custom integration/template exports
|
|
14
|
-
export { initIntegration, compileIntegration, loadRemoteIntegration } from './engine/custom-addons/integration.js'
|
|
15
|
-
export { initTemplate, compileTemplate, loadTemplate } from './engine/custom-addons/template.js'
|
|
16
|
-
|
|
17
|
-
// API exports
|
|
18
|
-
export {
|
|
19
|
-
fetchManifest,
|
|
20
|
-
fetchIntegration,
|
|
21
|
-
fetchIntegrations,
|
|
22
|
-
fetchIntegrationInfo,
|
|
23
|
-
fetchIntegrationFiles,
|
|
24
|
-
} from './api/fetch.js'
|
|
25
|
-
|
|
26
|
-
// Type exports
|
|
27
|
-
export type {
|
|
28
|
-
// Core types
|
|
29
|
-
PackageManager,
|
|
30
|
-
Category,
|
|
31
|
-
IntegrationType,
|
|
32
|
-
IntegrationPhase,
|
|
33
|
-
RouterMode,
|
|
34
|
-
|
|
35
|
-
// Option types
|
|
36
|
-
IntegrationOption,
|
|
37
|
-
IntegrationOptions,
|
|
38
|
-
|
|
39
|
-
// Hook types (code injection points)
|
|
40
|
-
HookType,
|
|
41
|
-
Hook,
|
|
42
|
-
Route,
|
|
43
|
-
EnvVar,
|
|
44
|
-
Command,
|
|
45
|
-
|
|
46
|
-
// Integration types
|
|
47
|
-
IntegrationInfo,
|
|
48
|
-
IntegrationCompiled,
|
|
49
|
-
CustomTemplateInfo,
|
|
50
|
-
CustomTemplateCompiled,
|
|
51
|
-
|
|
52
|
-
// Manifest types
|
|
53
|
-
ManifestIntegration,
|
|
54
|
-
Manifest,
|
|
55
|
-
|
|
56
|
-
// Project types
|
|
57
|
-
ProjectDefinition,
|
|
58
|
-
CompileOptions,
|
|
59
|
-
CompileOutput,
|
|
60
|
-
|
|
61
|
-
// Attribution types
|
|
62
|
-
LineAttribution,
|
|
63
|
-
AttributedFile,
|
|
64
|
-
AttributedCompileOutput,
|
|
65
|
-
} from './engine/types.js'
|
|
66
|
-
|
|
67
|
-
// Schema exports (for validation)
|
|
68
|
-
export {
|
|
69
|
-
CategorySchema,
|
|
70
|
-
IntegrationTypeSchema,
|
|
71
|
-
IntegrationPhaseSchema,
|
|
72
|
-
RouterModeSchema,
|
|
73
|
-
IntegrationOptionSchema,
|
|
74
|
-
IntegrationOptionsSchema,
|
|
75
|
-
HookSchema,
|
|
76
|
-
RouteSchema,
|
|
77
|
-
EnvVarSchema,
|
|
78
|
-
CommandSchema,
|
|
79
|
-
IntegrationInfoSchema,
|
|
80
|
-
IntegrationCompiledSchema,
|
|
81
|
-
CustomTemplateInfoSchema,
|
|
82
|
-
CustomTemplateCompiledSchema,
|
|
83
|
-
ManifestIntegrationSchema,
|
|
84
|
-
ManifestSchema,
|
|
85
|
-
} from './engine/types.js'
|
|
1
|
+
export { cli } from './cli.js'
|
package/src/mcp.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
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
|
+
getFrameworkByName,
|
|
12
|
+
getFrameworks,
|
|
13
|
+
populateAddOnOptionsDefaults,
|
|
14
|
+
} from '@tanstack/create'
|
|
15
|
+
|
|
16
|
+
import { registerDocTools } from './mcp/tools.js'
|
|
17
|
+
|
|
18
|
+
function createServer({
|
|
19
|
+
appName,
|
|
20
|
+
forcedAddOns = [],
|
|
21
|
+
}: {
|
|
22
|
+
appName?: string
|
|
23
|
+
forcedAddOns?: Array<string>
|
|
24
|
+
name?: string
|
|
25
|
+
}) {
|
|
26
|
+
const server = new McpServer({
|
|
27
|
+
name: `${appName} Application Builder`,
|
|
28
|
+
version: '1.0.0',
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
const frameworks = getFrameworks()
|
|
32
|
+
const frameworkNames = frameworks.map((framework) => framework.name)
|
|
33
|
+
|
|
34
|
+
server.tool(
|
|
35
|
+
'listTanStackAddOns',
|
|
36
|
+
'List the available add-ons for creating TanStack applications',
|
|
37
|
+
{
|
|
38
|
+
framework: z
|
|
39
|
+
.string()
|
|
40
|
+
.describe(
|
|
41
|
+
`The framework to use. Available frameworks: ${frameworkNames.join(', ')}`,
|
|
42
|
+
),
|
|
43
|
+
},
|
|
44
|
+
({ framework: frameworkName }) => {
|
|
45
|
+
const framework = getFrameworkByName(frameworkName)!
|
|
46
|
+
return {
|
|
47
|
+
content: [
|
|
48
|
+
{
|
|
49
|
+
type: 'text',
|
|
50
|
+
text: JSON.stringify(
|
|
51
|
+
framework
|
|
52
|
+
.getAddOns()
|
|
53
|
+
.filter((addOn) => addOn.modes.includes('file-router'))
|
|
54
|
+
.map((addOn) => ({
|
|
55
|
+
id: addOn.id,
|
|
56
|
+
name: addOn.name,
|
|
57
|
+
description: addOn.description,
|
|
58
|
+
options: addOn.options,
|
|
59
|
+
dependsOn: addOn.dependsOn,
|
|
60
|
+
})),
|
|
61
|
+
),
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
server.tool(
|
|
69
|
+
'createTanStackApplication',
|
|
70
|
+
'Create a new TanStack application',
|
|
71
|
+
{
|
|
72
|
+
framework: z
|
|
73
|
+
.string()
|
|
74
|
+
.describe(
|
|
75
|
+
`The framework to use. Available frameworks: ${frameworkNames.join(', ')}`,
|
|
76
|
+
),
|
|
77
|
+
projectName: z
|
|
78
|
+
.string()
|
|
79
|
+
.describe(
|
|
80
|
+
'The package.json module name of the application (will also be the directory name)',
|
|
81
|
+
),
|
|
82
|
+
cwd: z.string().describe('The directory to create the application in'),
|
|
83
|
+
addOns: z.array(z.string()).describe('Array of add-on IDs to install. Use listTanStackAddOns tool to see available add-ons and their configuration options. Example: ["prisma", "shadcn", "tanstack-query"]'),
|
|
84
|
+
addOnOptions: z.record(z.record(z.any())).optional().describe('Configuration options for add-ons. Format: {"addOnId": {"optionName": "value"}}. Use listTanStackAddOns to see available options for each add-on.'),
|
|
85
|
+
targetDir: z
|
|
86
|
+
.string()
|
|
87
|
+
.describe(
|
|
88
|
+
'The directory to create the application in. Use the absolute path of the directory you want the application to be created in',
|
|
89
|
+
),
|
|
90
|
+
},
|
|
91
|
+
async ({
|
|
92
|
+
framework: frameworkName,
|
|
93
|
+
projectName,
|
|
94
|
+
addOns,
|
|
95
|
+
addOnOptions,
|
|
96
|
+
cwd,
|
|
97
|
+
targetDir,
|
|
98
|
+
}) => {
|
|
99
|
+
const framework = getFrameworkByName(frameworkName)!
|
|
100
|
+
try {
|
|
101
|
+
process.chdir(cwd)
|
|
102
|
+
try {
|
|
103
|
+
const chosenAddOns = await finalizeAddOns(
|
|
104
|
+
framework,
|
|
105
|
+
'file-router',
|
|
106
|
+
Array.from(
|
|
107
|
+
new Set([
|
|
108
|
+
...(addOns as unknown as Array<string>),
|
|
109
|
+
...forcedAddOns,
|
|
110
|
+
]),
|
|
111
|
+
),
|
|
112
|
+
)
|
|
113
|
+
await createApp(createDefaultEnvironment(), {
|
|
114
|
+
projectName: projectName.replace(/^\//, './'),
|
|
115
|
+
targetDir,
|
|
116
|
+
framework,
|
|
117
|
+
typescript: true,
|
|
118
|
+
tailwind: true,
|
|
119
|
+
packageManager: 'pnpm',
|
|
120
|
+
mode: 'file-router',
|
|
121
|
+
chosenAddOns,
|
|
122
|
+
addOnOptions: addOnOptions || populateAddOnOptionsDefaults(chosenAddOns),
|
|
123
|
+
git: true,
|
|
124
|
+
})
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error(error)
|
|
127
|
+
return {
|
|
128
|
+
content: [
|
|
129
|
+
{ type: 'text', text: `Error creating application: ${error}` },
|
|
130
|
+
],
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
content: [{ type: 'text', text: 'Application created successfully' }],
|
|
135
|
+
}
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return {
|
|
138
|
+
content: [
|
|
139
|
+
{ type: 'text', text: `Error creating application: ${error}` },
|
|
140
|
+
],
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
// Register doc/ecosystem tools from TanStack API
|
|
147
|
+
registerDocTools(server)
|
|
148
|
+
|
|
149
|
+
return server
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function runMCPServer(
|
|
153
|
+
sse: boolean,
|
|
154
|
+
{
|
|
155
|
+
forcedAddOns,
|
|
156
|
+
appName,
|
|
157
|
+
name,
|
|
158
|
+
}: {
|
|
159
|
+
forcedMode?: string
|
|
160
|
+
forcedAddOns?: Array<string>
|
|
161
|
+
appName?: string
|
|
162
|
+
name?: string
|
|
163
|
+
},
|
|
164
|
+
) {
|
|
165
|
+
let transport: SSEServerTransport | null = null
|
|
166
|
+
|
|
167
|
+
const server = createServer({ appName, forcedAddOns, name })
|
|
168
|
+
if (sse) {
|
|
169
|
+
const app = express()
|
|
170
|
+
|
|
171
|
+
app.get('/sse', (req, res) => {
|
|
172
|
+
transport = new SSEServerTransport('/messages', res)
|
|
173
|
+
server.connect(transport)
|
|
174
|
+
})
|
|
175
|
+
|
|
176
|
+
app.post('/messages', (req, res) => {
|
|
177
|
+
if (transport) {
|
|
178
|
+
transport.handlePostMessage(req, res)
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
const port = process.env.PORT || 8080
|
|
183
|
+
app.listen(port, () => {
|
|
184
|
+
console.log(`Server is running on port http://localhost:${port}/sse`)
|
|
185
|
+
})
|
|
186
|
+
} else {
|
|
187
|
+
const transport = new StdioServerTransport()
|
|
188
|
+
await server.connect(transport)
|
|
189
|
+
}
|
|
190
|
+
}
|