@stacksfinder/mcp-server 1.5.1 → 1.6.0
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 +6 -1
- package/dist/data/compatibility_matrix.json +1160 -228
- package/dist/data/index.d.ts +2 -2
- package/dist/data/index.d.ts.map +1 -1
- package/dist/data/index.js +52 -43
- package/dist/data/index.js.map +1 -1
- package/dist/data/technology_scores.json +2936 -1030
- package/dist/http.js +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +463 -313
- package/dist/server.js.map +1 -1
- package/dist/tools/audit.d.ts +81 -1
- package/dist/tools/audit.d.ts.map +1 -1
- package/dist/tools/audit.js +358 -171
- package/dist/tools/audit.js.map +1 -1
- package/dist/tools/list-techs.d.ts +4 -4
- package/dist/tools/list-techs.js +1 -1
- package/dist/tools/list-techs.js.map +1 -1
- package/dist/tools/project-kit/generate.d.ts.map +1 -1
- package/dist/tools/project-kit/generate.js +2 -1
- package/dist/tools/project-kit/generate.js.map +1 -1
- package/dist/tools/project-kit/match-mcps.d.ts +1 -1
- package/dist/tools/project-kit/match-mcps.d.ts.map +1 -1
- package/dist/tools/project-kit/match-mcps.js +213 -199
- package/dist/tools/project-kit/match-mcps.js.map +1 -1
- package/dist/tools/recommend-demo.d.ts.map +1 -1
- package/dist/tools/recommend-demo.js +34 -10
- package/dist/tools/recommend-demo.js.map +1 -1
- package/package.json +75 -75
package/dist/server.js
CHANGED
|
@@ -1,287 +1,328 @@
|
|
|
1
|
-
import { McpServer } from
|
|
2
|
-
import { z } from
|
|
3
|
-
import { DATA_VERSION, CATEGORIES, CONTEXTS } from
|
|
4
|
-
import { listTechsToolDefinition, executeListTechs, ListTechsInputSchema } from
|
|
5
|
-
import { analyzeTechToolDefinition, executeAnalyzeTech, AnalyzeTechInputSchema } from
|
|
6
|
-
import { compareTechsToolDefinition, executeCompareTechs, CompareTechsInputSchema } from
|
|
7
|
-
import { recommendStackToolDefinition, executeRecommendStack, RecommendStackInputSchema } from
|
|
8
|
-
import { getBlueprintToolDefinition, executeGetBlueprint, GetBlueprintInputSchema, createBlueprintToolDefinition, executeCreateBlueprint, CreateBlueprintInputSchema } from
|
|
9
|
-
import { recommendStackDemoToolDefinition, executeRecommendStackDemo, RecommendStackDemoInputSchema } from
|
|
10
|
-
import { setupApiKeyToolDefinition, executeSetupApiKey, SetupApiKeyInputSchema, listApiKeysToolDefinition, executeListApiKeys, revokeApiKeyToolDefinition, executeRevokeApiKey, RevokeApiKeyInputSchema, createApiKeyToolDefinition, executeCreateApiKey, CreateApiKeyInputSchema } from
|
|
11
|
-
import { createAuditToolDefinition, executeCreateAudit, CreateAuditInputSchema, getAuditToolDefinition, executeGetAudit, GetAuditInputSchema, listAuditsToolDefinition, executeListAudits, ListAuditsInputSchema, compareAuditsToolDefinition, executeCompareAudits, CompareAuditsInputSchema, getAuditQuotaToolDefinition, executeGetAuditQuota, getMigrationRecommendationToolDefinition, executeGetMigrationRecommendation, GetMigrationRecommendationInputSchema } from
|
|
12
|
-
import { generateMCPKitTool, generateMCPKit, GenerateMCPKitInputSchema, analyzeRepoMcpsTool, analyzeRepo, AnalyzeRepoMCPsInputSchema, PRIORITIES, PROJECT_TYPES, SCALES } from
|
|
13
|
-
import { prepareMCPInstallationTool, prepareMCPInstallation } from
|
|
14
|
-
import { executeMCPInstallationTool, executeMCPInstallation } from
|
|
15
|
-
import { PrepareMCPInstallationInputSchema, ExecuteMCPInstallationInputSchema } from
|
|
16
|
-
import { checkCompatibilityToolDefinition, executeCheckCompatibility, CheckCompatibilityInputSchema } from
|
|
17
|
-
import { getWorkflowGuideToolDefinition, executeGetWorkflowGuide, GetWorkflowGuideInputSchema, WORKFLOW_GOALS, WORKFLOW_CONTEXTS, USER_TIERS } from
|
|
18
|
-
import { estimateProjectToolDefinition, executeEstimateProject, EstimateProjectInputSchema, getEstimateQuotaToolDefinition, executeGetEstimateQuota } from
|
|
19
|
-
import { info, debug } from
|
|
20
|
-
import { listTechnologiesAnnotations, analyzeTechAnnotations, compareTechsAnnotations, recommendStackDemoAnnotations, recommendStackAnnotations, getBlueprintAnnotations, createBlueprintAnnotations, setupApiKeyAnnotations, listApiKeysAnnotations, revokeApiKeyAnnotations, createApiKeyAnnotations, createAuditAnnotations, getAuditAnnotations, listAuditsAnnotations, compareAuditsAnnotations, getAuditQuotaAnnotations, getMigrationRecommendationAnnotations, generateMcpKitAnnotations, analyzeRepoMcpsAnnotations, prepareMcpInstallationAnnotations, executeMcpInstallationAnnotations, checkCompatibilityAnnotations, estimateProjectAnnotations, getEstimateQuotaAnnotations, getWorkflowGuideAnnotations } from
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
import { DATA_VERSION, CATEGORIES, CONTEXTS } from "./data/index.js";
|
|
4
|
+
import { listTechsToolDefinition, executeListTechs, ListTechsInputSchema, } from "./tools/list-techs.js";
|
|
5
|
+
import { analyzeTechToolDefinition, executeAnalyzeTech, AnalyzeTechInputSchema, } from "./tools/analyze.js";
|
|
6
|
+
import { compareTechsToolDefinition, executeCompareTechs, CompareTechsInputSchema, } from "./tools/compare.js";
|
|
7
|
+
import { recommendStackToolDefinition, executeRecommendStack, RecommendStackInputSchema, } from "./tools/recommend.js";
|
|
8
|
+
import { getBlueprintToolDefinition, executeGetBlueprint, GetBlueprintInputSchema, createBlueprintToolDefinition, executeCreateBlueprint, CreateBlueprintInputSchema, } from "./tools/blueprint.js";
|
|
9
|
+
import { recommendStackDemoToolDefinition, executeRecommendStackDemo, RecommendStackDemoInputSchema, } from "./tools/recommend-demo.js";
|
|
10
|
+
import { setupApiKeyToolDefinition, executeSetupApiKey, SetupApiKeyInputSchema, listApiKeysToolDefinition, executeListApiKeys, revokeApiKeyToolDefinition, executeRevokeApiKey, RevokeApiKeyInputSchema, createApiKeyToolDefinition, executeCreateApiKey, CreateApiKeyInputSchema, } from "./tools/api-keys.js";
|
|
11
|
+
import { createAuditToolDefinition, executeCreateAudit, CreateAuditInputSchema, getAuditToolDefinition, executeGetAudit, GetAuditInputSchema, listAuditsToolDefinition, executeListAudits, ListAuditsInputSchema, compareAuditsToolDefinition, executeCompareAudits, CompareAuditsInputSchema, getAuditQuotaToolDefinition, executeGetAuditQuota, getMigrationRecommendationToolDefinition, executeGetMigrationRecommendation, GetMigrationRecommendationInputSchema, importBetterTStackToolDefinition, executeImportBetterTStack, ImportBetterTStackInputSchema, } from "./tools/audit.js";
|
|
12
|
+
import { generateMCPKitTool, generateMCPKit, GenerateMCPKitInputSchema, analyzeRepoMcpsTool, analyzeRepo, AnalyzeRepoMCPsInputSchema, PRIORITIES, PROJECT_TYPES, SCALES, } from "./tools/project-kit/index.js";
|
|
13
|
+
import { prepareMCPInstallationTool, prepareMCPInstallation, } from "./tools/project-kit/prepare-installation.js";
|
|
14
|
+
import { executeMCPInstallationTool, executeMCPInstallation, } from "./tools/project-kit/execute-installation.js";
|
|
15
|
+
import { PrepareMCPInstallationInputSchema, ExecuteMCPInstallationInputSchema, } from "./tools/project-kit/installation-types.js";
|
|
16
|
+
import { checkCompatibilityToolDefinition, executeCheckCompatibility, CheckCompatibilityInputSchema, } from "./tools/check-compatibility.js";
|
|
17
|
+
import { getWorkflowGuideToolDefinition, executeGetWorkflowGuide, GetWorkflowGuideInputSchema, WORKFLOW_GOALS, WORKFLOW_CONTEXTS, USER_TIERS, } from "./tools/workflow-guide.js";
|
|
18
|
+
import { estimateProjectToolDefinition, executeEstimateProject, EstimateProjectInputSchema, getEstimateQuotaToolDefinition, executeGetEstimateQuota, } from "./tools/estimator.js";
|
|
19
|
+
import { info, debug } from "./utils/logger.js";
|
|
20
|
+
import { listTechnologiesAnnotations, analyzeTechAnnotations, compareTechsAnnotations, recommendStackDemoAnnotations, recommendStackAnnotations, getBlueprintAnnotations, createBlueprintAnnotations, setupApiKeyAnnotations, listApiKeysAnnotations, revokeApiKeyAnnotations, createApiKeyAnnotations, createAuditAnnotations, getAuditAnnotations, listAuditsAnnotations, compareAuditsAnnotations, getAuditQuotaAnnotations, getMigrationRecommendationAnnotations, generateMcpKitAnnotations, analyzeRepoMcpsAnnotations, prepareMcpInstallationAnnotations, executeMcpInstallationAnnotations, checkCompatibilityAnnotations, estimateProjectAnnotations, getEstimateQuotaAnnotations, getWorkflowGuideAnnotations, } from "./annotations.js";
|
|
21
21
|
/**
|
|
22
22
|
* Create and configure the MCP server.
|
|
23
23
|
*/
|
|
24
24
|
export function createServer() {
|
|
25
25
|
const server = new McpServer({
|
|
26
|
-
name:
|
|
27
|
-
version:
|
|
26
|
+
name: "stacksfinder",
|
|
27
|
+
version: "1.0.0",
|
|
28
28
|
});
|
|
29
29
|
info(`StacksFinder MCP Server v1.0.0 (data version: ${DATA_VERSION})`);
|
|
30
30
|
// Register list_technologies tool (local, discovery)
|
|
31
31
|
server.registerTool(listTechsToolDefinition.name, {
|
|
32
|
-
title:
|
|
32
|
+
title: "List Technologies",
|
|
33
33
|
description: listTechsToolDefinition.description,
|
|
34
34
|
inputSchema: {
|
|
35
|
-
category: z.enum(CATEGORIES).optional().describe(
|
|
35
|
+
category: z.enum(CATEGORIES).optional().describe("Filter by category"),
|
|
36
36
|
},
|
|
37
|
-
annotations: listTechnologiesAnnotations
|
|
37
|
+
annotations: listTechnologiesAnnotations,
|
|
38
38
|
}, async (args) => {
|
|
39
|
-
debug(
|
|
39
|
+
debug("list_technologies called", args);
|
|
40
40
|
const input = ListTechsInputSchema.parse(args);
|
|
41
41
|
const text = executeListTechs(input);
|
|
42
42
|
return {
|
|
43
|
-
content: [{ type:
|
|
43
|
+
content: [{ type: "text", text }],
|
|
44
44
|
};
|
|
45
45
|
});
|
|
46
46
|
// Register analyze_tech tool (local)
|
|
47
47
|
server.registerTool(analyzeTechToolDefinition.name, {
|
|
48
|
-
title:
|
|
48
|
+
title: "Analyze Technology",
|
|
49
49
|
description: analyzeTechToolDefinition.description,
|
|
50
50
|
inputSchema: {
|
|
51
|
-
technology: z.string().min(1).describe(
|
|
52
|
-
context: z.enum(CONTEXTS).optional().describe(
|
|
51
|
+
technology: z.string().min(1).describe("Technology ID to analyze"),
|
|
52
|
+
context: z.enum(CONTEXTS).optional().describe("Context for scoring"),
|
|
53
53
|
},
|
|
54
|
-
annotations: analyzeTechAnnotations
|
|
54
|
+
annotations: analyzeTechAnnotations,
|
|
55
55
|
}, async (args) => {
|
|
56
|
-
debug(
|
|
56
|
+
debug("analyze_tech called", args);
|
|
57
57
|
const input = AnalyzeTechInputSchema.parse(args);
|
|
58
58
|
const { text, isError } = executeAnalyzeTech(input);
|
|
59
59
|
return {
|
|
60
|
-
content: [{ type:
|
|
61
|
-
isError
|
|
60
|
+
content: [{ type: "text", text }],
|
|
61
|
+
isError,
|
|
62
62
|
};
|
|
63
63
|
});
|
|
64
64
|
// Register compare_techs tool (local)
|
|
65
65
|
server.registerTool(compareTechsToolDefinition.name, {
|
|
66
|
-
title:
|
|
66
|
+
title: "Compare Technologies",
|
|
67
67
|
description: compareTechsToolDefinition.description,
|
|
68
68
|
inputSchema: {
|
|
69
|
-
technologies: z
|
|
70
|
-
|
|
69
|
+
technologies: z
|
|
70
|
+
.array(z.string().min(1))
|
|
71
|
+
.min(2)
|
|
72
|
+
.max(4)
|
|
73
|
+
.describe("Technologies to compare"),
|
|
74
|
+
context: z.enum(CONTEXTS).optional().describe("Context for scoring"),
|
|
71
75
|
},
|
|
72
|
-
annotations: compareTechsAnnotations
|
|
76
|
+
annotations: compareTechsAnnotations,
|
|
73
77
|
}, async (args) => {
|
|
74
|
-
debug(
|
|
78
|
+
debug("compare_techs called", args);
|
|
75
79
|
const input = CompareTechsInputSchema.parse(args);
|
|
76
80
|
const { text, isError } = executeCompareTechs(input);
|
|
77
81
|
return {
|
|
78
|
-
content: [{ type:
|
|
79
|
-
isError
|
|
82
|
+
content: [{ type: "text", text }],
|
|
83
|
+
isError,
|
|
80
84
|
};
|
|
81
85
|
});
|
|
82
86
|
// Register recommend_stack_demo tool (FREE, local scoring, 1/day limit)
|
|
83
87
|
server.registerTool(recommendStackDemoToolDefinition.name, {
|
|
84
|
-
title:
|
|
88
|
+
title: "Recommend Stack (Demo)",
|
|
85
89
|
description: recommendStackDemoToolDefinition.description,
|
|
86
90
|
inputSchema: {
|
|
87
91
|
projectType: z
|
|
88
92
|
.enum([
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
93
|
+
"web-app",
|
|
94
|
+
"mobile-app",
|
|
95
|
+
"api",
|
|
96
|
+
"desktop",
|
|
97
|
+
"cli",
|
|
98
|
+
"library",
|
|
99
|
+
"e-commerce",
|
|
100
|
+
"saas",
|
|
101
|
+
"marketplace",
|
|
98
102
|
])
|
|
99
|
-
.describe(
|
|
100
|
-
scale: z
|
|
103
|
+
.describe("Type of project"),
|
|
104
|
+
scale: z
|
|
105
|
+
.enum(["mvp", "startup", "growth", "enterprise"])
|
|
106
|
+
.optional()
|
|
107
|
+
.describe("Project scale"),
|
|
101
108
|
},
|
|
102
|
-
annotations: recommendStackDemoAnnotations
|
|
109
|
+
annotations: recommendStackDemoAnnotations,
|
|
103
110
|
}, async (args) => {
|
|
104
|
-
debug(
|
|
111
|
+
debug("recommend_stack_demo called", args);
|
|
105
112
|
const input = RecommendStackDemoInputSchema.parse(args);
|
|
106
113
|
const { text, isError } = executeRecommendStackDemo(input);
|
|
107
114
|
return {
|
|
108
|
-
content: [{ type:
|
|
109
|
-
isError
|
|
115
|
+
content: [{ type: "text", text }],
|
|
116
|
+
isError,
|
|
110
117
|
};
|
|
111
118
|
});
|
|
112
119
|
// Register recommend_stack tool (API-based, requires API key)
|
|
113
120
|
server.registerTool(recommendStackToolDefinition.name, {
|
|
114
|
-
title:
|
|
121
|
+
title: "Recommend Stack",
|
|
115
122
|
description: recommendStackToolDefinition.description,
|
|
116
123
|
inputSchema: {
|
|
117
124
|
projectType: z
|
|
118
125
|
.enum([
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
126
|
+
"web-app",
|
|
127
|
+
"mobile-app",
|
|
128
|
+
"api",
|
|
129
|
+
"desktop",
|
|
130
|
+
"cli",
|
|
131
|
+
"library",
|
|
132
|
+
"e-commerce",
|
|
133
|
+
"saas",
|
|
134
|
+
"marketplace",
|
|
128
135
|
])
|
|
129
|
-
.describe(
|
|
130
|
-
scale: z
|
|
136
|
+
.describe("Type of project"),
|
|
137
|
+
scale: z
|
|
138
|
+
.enum(["mvp", "startup", "growth", "enterprise"])
|
|
139
|
+
.optional()
|
|
140
|
+
.describe("Project scale"),
|
|
131
141
|
priorities: z
|
|
132
142
|
.array(z.enum([
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
143
|
+
"time-to-market",
|
|
144
|
+
"scalability",
|
|
145
|
+
"developer-experience",
|
|
146
|
+
"cost-efficiency",
|
|
147
|
+
"performance",
|
|
148
|
+
"security",
|
|
149
|
+
"maintainability",
|
|
140
150
|
]))
|
|
141
151
|
.max(3)
|
|
142
152
|
.optional()
|
|
143
|
-
.describe(
|
|
144
|
-
constraints: z
|
|
153
|
+
.describe("Top priorities (max 3)"),
|
|
154
|
+
constraints: z
|
|
155
|
+
.array(z.string())
|
|
156
|
+
.optional()
|
|
157
|
+
.describe("Project constraints"),
|
|
145
158
|
},
|
|
146
|
-
annotations: recommendStackAnnotations
|
|
159
|
+
annotations: recommendStackAnnotations,
|
|
147
160
|
}, async (args) => {
|
|
148
|
-
debug(
|
|
161
|
+
debug("recommend_stack called", args);
|
|
149
162
|
const input = RecommendStackInputSchema.parse(args);
|
|
150
163
|
const { text, isError } = await executeRecommendStack(input);
|
|
151
164
|
return {
|
|
152
|
-
content: [{ type:
|
|
153
|
-
isError
|
|
165
|
+
content: [{ type: "text", text }],
|
|
166
|
+
isError,
|
|
154
167
|
};
|
|
155
168
|
});
|
|
156
169
|
// Register get_blueprint tool (API-based)
|
|
157
170
|
server.registerTool(getBlueprintToolDefinition.name, {
|
|
158
|
-
title:
|
|
171
|
+
title: "Get Blueprint",
|
|
159
172
|
description: getBlueprintToolDefinition.description,
|
|
160
173
|
inputSchema: {
|
|
161
|
-
blueprintId: z.string().uuid().describe(
|
|
174
|
+
blueprintId: z.string().uuid().describe("Blueprint UUID"),
|
|
162
175
|
},
|
|
163
|
-
annotations: getBlueprintAnnotations
|
|
176
|
+
annotations: getBlueprintAnnotations,
|
|
164
177
|
}, async (args) => {
|
|
165
|
-
debug(
|
|
178
|
+
debug("get_blueprint called", args);
|
|
166
179
|
const input = GetBlueprintInputSchema.parse(args);
|
|
167
180
|
const { text, isError } = await executeGetBlueprint(input);
|
|
168
181
|
return {
|
|
169
|
-
content: [{ type:
|
|
170
|
-
isError
|
|
182
|
+
content: [{ type: "text", text }],
|
|
183
|
+
isError,
|
|
171
184
|
};
|
|
172
185
|
});
|
|
173
186
|
// Register create_blueprint tool (API-based, requires API key with blueprint:write)
|
|
174
187
|
server.registerTool(createBlueprintToolDefinition.name, {
|
|
175
|
-
title:
|
|
188
|
+
title: "Create Blueprint",
|
|
176
189
|
description: createBlueprintToolDefinition.description,
|
|
177
190
|
inputSchema: {
|
|
178
|
-
projectName: z
|
|
191
|
+
projectName: z
|
|
192
|
+
.string()
|
|
193
|
+
.max(100)
|
|
194
|
+
.optional()
|
|
195
|
+
.describe("Project name (optional)"),
|
|
179
196
|
projectType: z
|
|
180
197
|
.enum([
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
198
|
+
"web-app",
|
|
199
|
+
"mobile-app",
|
|
200
|
+
"api",
|
|
201
|
+
"desktop",
|
|
202
|
+
"cli",
|
|
203
|
+
"library",
|
|
204
|
+
"e-commerce",
|
|
205
|
+
"saas",
|
|
206
|
+
"marketplace",
|
|
190
207
|
])
|
|
191
|
-
.describe(
|
|
192
|
-
scale: z
|
|
193
|
-
|
|
208
|
+
.describe("Type of project"),
|
|
209
|
+
scale: z
|
|
210
|
+
.enum(["mvp", "startup", "growth", "enterprise"])
|
|
211
|
+
.describe("Project scale"),
|
|
212
|
+
projectDescription: z
|
|
213
|
+
.string()
|
|
214
|
+
.max(2000)
|
|
215
|
+
.optional()
|
|
216
|
+
.describe("Brief description (optional)"),
|
|
194
217
|
priorities: z
|
|
195
218
|
.array(z.enum([
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
219
|
+
"time-to-market",
|
|
220
|
+
"scalability",
|
|
221
|
+
"developer-experience",
|
|
222
|
+
"cost-efficiency",
|
|
223
|
+
"performance",
|
|
224
|
+
"security",
|
|
225
|
+
"maintainability",
|
|
203
226
|
]))
|
|
204
227
|
.max(3)
|
|
205
228
|
.optional()
|
|
206
|
-
.describe(
|
|
207
|
-
constraints: z
|
|
208
|
-
|
|
229
|
+
.describe("Top 3 priorities (optional)"),
|
|
230
|
+
constraints: z
|
|
231
|
+
.array(z.string())
|
|
232
|
+
.max(20)
|
|
233
|
+
.optional()
|
|
234
|
+
.describe("Technology constraint IDs (optional)"),
|
|
235
|
+
waitForCompletion: z
|
|
236
|
+
.boolean()
|
|
237
|
+
.optional()
|
|
238
|
+
.describe("Wait for completion (default: true)"),
|
|
209
239
|
},
|
|
210
|
-
annotations: createBlueprintAnnotations
|
|
240
|
+
annotations: createBlueprintAnnotations,
|
|
211
241
|
}, async (args) => {
|
|
212
|
-
debug(
|
|
242
|
+
debug("create_blueprint called", args);
|
|
213
243
|
const input = CreateBlueprintInputSchema.parse(args);
|
|
214
244
|
const { text, isError } = await executeCreateBlueprint(input);
|
|
215
245
|
return {
|
|
216
|
-
content: [{ type:
|
|
217
|
-
isError
|
|
246
|
+
content: [{ type: "text", text }],
|
|
247
|
+
isError,
|
|
218
248
|
};
|
|
219
249
|
});
|
|
220
250
|
// Register setup_api_key tool (API-based, no auth required)
|
|
221
251
|
server.registerTool(setupApiKeyToolDefinition.name, {
|
|
222
|
-
title:
|
|
252
|
+
title: "Setup API Key",
|
|
223
253
|
description: setupApiKeyToolDefinition.description,
|
|
224
254
|
inputSchema: {
|
|
225
|
-
email: z.string().email().describe(
|
|
226
|
-
password: z
|
|
227
|
-
|
|
255
|
+
email: z.string().email().describe("Your StacksFinder account email"),
|
|
256
|
+
password: z
|
|
257
|
+
.string()
|
|
258
|
+
.min(1)
|
|
259
|
+
.describe("Your StacksFinder account password"),
|
|
260
|
+
keyName: z
|
|
261
|
+
.string()
|
|
262
|
+
.max(100)
|
|
263
|
+
.optional()
|
|
264
|
+
.describe("Optional name for the API key"),
|
|
228
265
|
},
|
|
229
|
-
annotations: setupApiKeyAnnotations
|
|
266
|
+
annotations: setupApiKeyAnnotations,
|
|
230
267
|
}, async (args) => {
|
|
231
|
-
debug(
|
|
268
|
+
debug("setup_api_key called", args.email);
|
|
232
269
|
const input = SetupApiKeyInputSchema.parse(args);
|
|
233
270
|
const { text, isError } = await executeSetupApiKey(input);
|
|
234
271
|
return {
|
|
235
|
-
content: [{ type:
|
|
236
|
-
isError
|
|
272
|
+
content: [{ type: "text", text }],
|
|
273
|
+
isError,
|
|
237
274
|
};
|
|
238
275
|
});
|
|
239
276
|
// Register list_api_keys tool (API-based, requires API key)
|
|
240
277
|
server.registerTool(listApiKeysToolDefinition.name, {
|
|
241
|
-
title:
|
|
278
|
+
title: "List API Keys",
|
|
242
279
|
description: listApiKeysToolDefinition.description,
|
|
243
280
|
inputSchema: {},
|
|
244
|
-
annotations: listApiKeysAnnotations
|
|
281
|
+
annotations: listApiKeysAnnotations,
|
|
245
282
|
}, async () => {
|
|
246
|
-
debug(
|
|
283
|
+
debug("list_api_keys called");
|
|
247
284
|
const { text, isError } = await executeListApiKeys();
|
|
248
285
|
return {
|
|
249
|
-
content: [{ type:
|
|
250
|
-
isError
|
|
286
|
+
content: [{ type: "text", text }],
|
|
287
|
+
isError,
|
|
251
288
|
};
|
|
252
289
|
});
|
|
253
290
|
// Register revoke_api_key tool (API-based, requires API key)
|
|
254
291
|
server.registerTool(revokeApiKeyToolDefinition.name, {
|
|
255
|
-
title:
|
|
292
|
+
title: "Revoke API Key",
|
|
256
293
|
description: revokeApiKeyToolDefinition.description,
|
|
257
294
|
inputSchema: {
|
|
258
|
-
keyId: z.string().uuid().describe(
|
|
295
|
+
keyId: z.string().uuid().describe("The UUID of the API key to revoke"),
|
|
259
296
|
},
|
|
260
|
-
annotations: revokeApiKeyAnnotations
|
|
297
|
+
annotations: revokeApiKeyAnnotations,
|
|
261
298
|
}, async (args) => {
|
|
262
|
-
debug(
|
|
299
|
+
debug("revoke_api_key called", args.keyId);
|
|
263
300
|
const input = RevokeApiKeyInputSchema.parse(args);
|
|
264
301
|
const { text, isError } = await executeRevokeApiKey(input);
|
|
265
302
|
return {
|
|
266
|
-
content: [{ type:
|
|
267
|
-
isError
|
|
303
|
+
content: [{ type: "text", text }],
|
|
304
|
+
isError,
|
|
268
305
|
};
|
|
269
306
|
});
|
|
270
307
|
// Register create_api_key tool (OAuth-based, no email/password required)
|
|
271
308
|
server.registerTool(createApiKeyToolDefinition.name, {
|
|
272
|
-
title:
|
|
309
|
+
title: "Create API Key",
|
|
273
310
|
description: createApiKeyToolDefinition.description,
|
|
274
311
|
inputSchema: {
|
|
275
|
-
keyName: z
|
|
312
|
+
keyName: z
|
|
313
|
+
.string()
|
|
314
|
+
.max(100)
|
|
315
|
+
.optional()
|
|
316
|
+
.describe("Optional name for the API key"),
|
|
276
317
|
},
|
|
277
|
-
annotations: createApiKeyAnnotations
|
|
318
|
+
annotations: createApiKeyAnnotations,
|
|
278
319
|
}, async (args) => {
|
|
279
|
-
debug(
|
|
320
|
+
debug("create_api_key called");
|
|
280
321
|
const input = CreateApiKeyInputSchema.parse(args);
|
|
281
322
|
const { text, isError } = await executeCreateApiKey(input);
|
|
282
323
|
return {
|
|
283
|
-
content: [{ type:
|
|
284
|
-
isError
|
|
324
|
+
content: [{ type: "text", text }],
|
|
325
|
+
isError,
|
|
285
326
|
};
|
|
286
327
|
});
|
|
287
328
|
// ========================================================================
|
|
@@ -289,112 +330,141 @@ export function createServer() {
|
|
|
289
330
|
// ========================================================================
|
|
290
331
|
// Register create_audit tool (API-based, requires API key with audit:write)
|
|
291
332
|
server.registerTool(createAuditToolDefinition.name, {
|
|
292
|
-
title:
|
|
333
|
+
title: "Create Technical Debt Audit",
|
|
293
334
|
description: createAuditToolDefinition.description,
|
|
294
335
|
inputSchema: {
|
|
295
|
-
name: z.string().min(1).max(200).describe(
|
|
336
|
+
name: z.string().min(1).max(200).describe("Name for the audit report"),
|
|
296
337
|
technologies: z
|
|
297
338
|
.array(z.object({
|
|
298
|
-
name: z.string().min(1).describe(
|
|
299
|
-
version: z.string().optional().describe(
|
|
300
|
-
category: z.string().optional().describe(
|
|
339
|
+
name: z.string().min(1).describe("Technology name"),
|
|
340
|
+
version: z.string().optional().describe("Version string"),
|
|
341
|
+
category: z.string().optional().describe("Category"),
|
|
301
342
|
}))
|
|
302
343
|
.min(1)
|
|
303
344
|
.max(50)
|
|
304
|
-
.describe(
|
|
345
|
+
.describe("Technologies to audit"),
|
|
305
346
|
},
|
|
306
|
-
annotations: createAuditAnnotations
|
|
347
|
+
annotations: createAuditAnnotations,
|
|
307
348
|
}, async (args) => {
|
|
308
|
-
debug(
|
|
349
|
+
debug("create_audit called", args);
|
|
309
350
|
const input = CreateAuditInputSchema.parse(args);
|
|
310
351
|
const { text, isError } = await executeCreateAudit(input);
|
|
311
352
|
return {
|
|
312
|
-
content: [{ type:
|
|
313
|
-
isError
|
|
353
|
+
content: [{ type: "text", text }],
|
|
354
|
+
isError,
|
|
314
355
|
};
|
|
315
356
|
});
|
|
316
357
|
// Register get_audit tool (API-based, requires API key with audit:read)
|
|
317
358
|
server.registerTool(getAuditToolDefinition.name, {
|
|
318
|
-
title:
|
|
359
|
+
title: "Get Audit Report",
|
|
319
360
|
description: getAuditToolDefinition.description,
|
|
320
361
|
inputSchema: {
|
|
321
|
-
auditId: z.string().uuid().describe(
|
|
362
|
+
auditId: z.string().uuid().describe("Audit report UUID"),
|
|
322
363
|
},
|
|
323
|
-
annotations: getAuditAnnotations
|
|
364
|
+
annotations: getAuditAnnotations,
|
|
324
365
|
}, async (args) => {
|
|
325
|
-
debug(
|
|
366
|
+
debug("get_audit called", args);
|
|
326
367
|
const input = GetAuditInputSchema.parse(args);
|
|
327
368
|
const { text, isError } = await executeGetAudit(input);
|
|
328
369
|
return {
|
|
329
|
-
content: [{ type:
|
|
330
|
-
isError
|
|
370
|
+
content: [{ type: "text", text }],
|
|
371
|
+
isError,
|
|
331
372
|
};
|
|
332
373
|
});
|
|
333
374
|
// Register list_audits tool (API-based, requires API key with audit:read)
|
|
334
375
|
server.registerTool(listAuditsToolDefinition.name, {
|
|
335
|
-
title:
|
|
376
|
+
title: "List Audit Reports",
|
|
336
377
|
description: listAuditsToolDefinition.description,
|
|
337
378
|
inputSchema: {
|
|
338
|
-
limit: z.number().min(1).max(50).optional().describe(
|
|
339
|
-
offset: z.number().min(0).optional().describe(
|
|
379
|
+
limit: z.number().min(1).max(50).optional().describe("Max results"),
|
|
380
|
+
offset: z.number().min(0).optional().describe("Pagination offset"),
|
|
340
381
|
},
|
|
341
|
-
annotations: listAuditsAnnotations
|
|
382
|
+
annotations: listAuditsAnnotations,
|
|
342
383
|
}, async (args) => {
|
|
343
|
-
debug(
|
|
384
|
+
debug("list_audits called", args);
|
|
344
385
|
const input = ListAuditsInputSchema.parse(args);
|
|
345
386
|
const { text, isError } = await executeListAudits(input);
|
|
346
387
|
return {
|
|
347
|
-
content: [{ type:
|
|
348
|
-
isError
|
|
388
|
+
content: [{ type: "text", text }],
|
|
389
|
+
isError,
|
|
349
390
|
};
|
|
350
391
|
});
|
|
351
392
|
// Register compare_audits tool (API-based, requires API key with audit:read)
|
|
352
393
|
server.registerTool(compareAuditsToolDefinition.name, {
|
|
353
|
-
title:
|
|
394
|
+
title: "Compare Audit Reports",
|
|
354
395
|
description: compareAuditsToolDefinition.description,
|
|
355
396
|
inputSchema: {
|
|
356
|
-
baseAuditId: z.string().uuid().describe(
|
|
357
|
-
compareAuditId: z.string().uuid().describe(
|
|
397
|
+
baseAuditId: z.string().uuid().describe("Base (older) audit ID"),
|
|
398
|
+
compareAuditId: z.string().uuid().describe("Compare (newer) audit ID"),
|
|
358
399
|
},
|
|
359
|
-
annotations: compareAuditsAnnotations
|
|
400
|
+
annotations: compareAuditsAnnotations,
|
|
360
401
|
}, async (args) => {
|
|
361
|
-
debug(
|
|
402
|
+
debug("compare_audits called", args);
|
|
362
403
|
const input = CompareAuditsInputSchema.parse(args);
|
|
363
404
|
const { text, isError } = await executeCompareAudits(input);
|
|
364
405
|
return {
|
|
365
|
-
content: [{ type:
|
|
366
|
-
isError
|
|
406
|
+
content: [{ type: "text", text }],
|
|
407
|
+
isError,
|
|
367
408
|
};
|
|
368
409
|
});
|
|
369
410
|
// Register get_audit_quota tool (API-based, requires API key)
|
|
370
411
|
server.registerTool(getAuditQuotaToolDefinition.name, {
|
|
371
|
-
title:
|
|
412
|
+
title: "Get Audit Quota",
|
|
372
413
|
description: getAuditQuotaToolDefinition.description,
|
|
373
414
|
inputSchema: {},
|
|
374
|
-
annotations: getAuditQuotaAnnotations
|
|
415
|
+
annotations: getAuditQuotaAnnotations,
|
|
375
416
|
}, async () => {
|
|
376
|
-
debug(
|
|
417
|
+
debug("get_audit_quota called");
|
|
377
418
|
const { text, isError } = await executeGetAuditQuota();
|
|
378
419
|
return {
|
|
379
|
-
content: [{ type:
|
|
380
|
-
isError
|
|
420
|
+
content: [{ type: "text", text }],
|
|
421
|
+
isError,
|
|
381
422
|
};
|
|
382
423
|
});
|
|
383
424
|
// Register get_migration_recommendation tool (API-based, requires API key with audit:read)
|
|
384
425
|
server.registerTool(getMigrationRecommendationToolDefinition.name, {
|
|
385
|
-
title:
|
|
426
|
+
title: "Get Migration Recommendation",
|
|
386
427
|
description: getMigrationRecommendationToolDefinition.description,
|
|
387
428
|
inputSchema: {
|
|
388
|
-
auditId: z
|
|
429
|
+
auditId: z
|
|
430
|
+
.string()
|
|
431
|
+
.uuid()
|
|
432
|
+
.describe("Audit report UUID to analyze for migration"),
|
|
389
433
|
},
|
|
390
|
-
annotations: getMigrationRecommendationAnnotations
|
|
434
|
+
annotations: getMigrationRecommendationAnnotations,
|
|
391
435
|
}, async (args) => {
|
|
392
|
-
debug(
|
|
436
|
+
debug("get_migration_recommendation called", args);
|
|
393
437
|
const input = GetMigrationRecommendationInputSchema.parse(args);
|
|
394
438
|
const { text, isError } = await executeGetMigrationRecommendation(input);
|
|
395
439
|
return {
|
|
396
|
-
content: [{ type:
|
|
397
|
-
isError
|
|
440
|
+
content: [{ type: "text", text }],
|
|
441
|
+
isError,
|
|
442
|
+
};
|
|
443
|
+
});
|
|
444
|
+
// Register import_better_t_stack tool (API-based, requires API key with audit:write)
|
|
445
|
+
server.registerTool(importBetterTStackToolDefinition.name, {
|
|
446
|
+
title: "Import Better-T-Stack Project",
|
|
447
|
+
description: importBetterTStackToolDefinition.description,
|
|
448
|
+
inputSchema: {
|
|
449
|
+
type: z.enum(["github", "package-json"]).describe("Import source type"),
|
|
450
|
+
url: z
|
|
451
|
+
.string()
|
|
452
|
+
.optional()
|
|
453
|
+
.describe("GitHub repository URL (for type=github)"),
|
|
454
|
+
content: z
|
|
455
|
+
.string()
|
|
456
|
+
.optional()
|
|
457
|
+
.describe("Raw package.json content (for type=package-json)"),
|
|
458
|
+
name: z.string().max(200).optional().describe("Custom audit name"),
|
|
459
|
+
},
|
|
460
|
+
annotations: createAuditAnnotations, // Reuse audit annotations
|
|
461
|
+
}, async (args) => {
|
|
462
|
+
debug("import_better_t_stack called", args);
|
|
463
|
+
const input = ImportBetterTStackInputSchema.parse(args);
|
|
464
|
+
const { text, isError } = await executeImportBetterTStack(input);
|
|
465
|
+
return {
|
|
466
|
+
content: [{ type: "text", text }],
|
|
467
|
+
isError,
|
|
398
468
|
};
|
|
399
469
|
});
|
|
400
470
|
// ========================================================================
|
|
@@ -402,81 +472,133 @@ export function createServer() {
|
|
|
402
472
|
// ========================================================================
|
|
403
473
|
// Register generate_mcp_kit tool (local, no API key required)
|
|
404
474
|
server.registerTool(generateMCPKitTool.name, {
|
|
405
|
-
title:
|
|
475
|
+
title: "Generate MCP Kit",
|
|
406
476
|
description: generateMCPKitTool.description,
|
|
407
477
|
inputSchema: {
|
|
408
|
-
projectDescription: z
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
478
|
+
projectDescription: z
|
|
479
|
+
.string()
|
|
480
|
+
.min(50)
|
|
481
|
+
.max(5000)
|
|
482
|
+
.describe("Describe your project (50-5000 chars)"),
|
|
483
|
+
priorities: z
|
|
484
|
+
.array(z.enum(PRIORITIES))
|
|
485
|
+
.max(3)
|
|
486
|
+
.optional()
|
|
487
|
+
.describe("Top priorities (max 3)"),
|
|
488
|
+
constraints: z
|
|
489
|
+
.array(z.string())
|
|
490
|
+
.optional()
|
|
491
|
+
.describe("Tech constraints (e.g., must-use-postgresql)"),
|
|
492
|
+
projectType: z
|
|
493
|
+
.enum(PROJECT_TYPES)
|
|
494
|
+
.optional()
|
|
495
|
+
.describe("Project type (if known)"),
|
|
496
|
+
scale: z.enum(SCALES).optional().describe("Project scale (if known)"),
|
|
413
497
|
},
|
|
414
|
-
annotations: generateMcpKitAnnotations
|
|
498
|
+
annotations: generateMcpKitAnnotations,
|
|
415
499
|
}, async (args) => {
|
|
416
|
-
debug(
|
|
500
|
+
debug("generate_mcp_kit called", args);
|
|
417
501
|
const input = GenerateMCPKitInputSchema.parse(args);
|
|
418
502
|
const result = generateMCPKit(input);
|
|
419
503
|
return {
|
|
420
|
-
content: [{ type:
|
|
504
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
421
505
|
};
|
|
422
506
|
});
|
|
423
507
|
// Register analyze_repo_mcps tool (local, no API key required)
|
|
424
508
|
server.registerTool(analyzeRepoMcpsTool.name, {
|
|
425
|
-
title:
|
|
509
|
+
title: "Analyze Repository MCPs",
|
|
426
510
|
description: analyzeRepoMcpsTool.description,
|
|
427
511
|
inputSchema: {
|
|
428
|
-
includeInstalled: z
|
|
429
|
-
|
|
430
|
-
|
|
512
|
+
includeInstalled: z
|
|
513
|
+
.boolean()
|
|
514
|
+
.optional()
|
|
515
|
+
.describe("Include already installed MCPs (default: false)"),
|
|
516
|
+
mcpConfigPath: z
|
|
517
|
+
.string()
|
|
518
|
+
.optional()
|
|
519
|
+
.describe("Override path to MCP configuration file"),
|
|
520
|
+
workspaceRoot: z
|
|
521
|
+
.string()
|
|
522
|
+
.optional()
|
|
523
|
+
.describe("Override workspace root directory (default: current directory)"),
|
|
431
524
|
},
|
|
432
|
-
annotations: analyzeRepoMcpsAnnotations
|
|
525
|
+
annotations: analyzeRepoMcpsAnnotations,
|
|
433
526
|
}, async (args) => {
|
|
434
|
-
debug(
|
|
527
|
+
debug("analyze_repo_mcps called", args);
|
|
435
528
|
const input = AnalyzeRepoMCPsInputSchema.parse(args);
|
|
436
529
|
const result = await analyzeRepo(input);
|
|
437
530
|
// Format as markdown for better readability
|
|
438
531
|
return {
|
|
439
|
-
content: [{ type:
|
|
532
|
+
content: [{ type: "text", text: formatAnalysisResult(result) }],
|
|
440
533
|
};
|
|
441
534
|
});
|
|
442
535
|
// Register prepare_mcp_installation tool (local, no API key required)
|
|
443
536
|
server.registerTool(prepareMCPInstallationTool.name, {
|
|
444
|
-
title:
|
|
537
|
+
title: "Prepare MCP Installation",
|
|
445
538
|
description: prepareMCPInstallationTool.description,
|
|
446
539
|
inputSchema: {
|
|
447
|
-
workspaceRoot: z
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
540
|
+
workspaceRoot: z
|
|
541
|
+
.string()
|
|
542
|
+
.optional()
|
|
543
|
+
.describe("Workspace root directory (default: current directory)"),
|
|
544
|
+
mcpConfigPath: z
|
|
545
|
+
.string()
|
|
546
|
+
.optional()
|
|
547
|
+
.describe("Override path to existing MCP configuration file"),
|
|
548
|
+
includeInstalled: z
|
|
549
|
+
.boolean()
|
|
550
|
+
.optional()
|
|
551
|
+
.describe("Include already installed MCPs in the preparation (default: false)"),
|
|
552
|
+
envMcpPath: z
|
|
553
|
+
.string()
|
|
554
|
+
.optional()
|
|
555
|
+
.describe("Path where .env-mcp will be created (default: .env-mcp in workspaceRoot)"),
|
|
451
556
|
},
|
|
452
|
-
annotations: prepareMcpInstallationAnnotations
|
|
557
|
+
annotations: prepareMcpInstallationAnnotations,
|
|
453
558
|
}, async (args) => {
|
|
454
|
-
debug(
|
|
559
|
+
debug("prepare_mcp_installation called", args);
|
|
455
560
|
const input = PrepareMCPInstallationInputSchema.parse(args);
|
|
456
561
|
const result = await prepareMCPInstallation(input);
|
|
457
562
|
return {
|
|
458
|
-
content: [
|
|
563
|
+
content: [
|
|
564
|
+
{
|
|
565
|
+
type: "text",
|
|
566
|
+
text: result.message + "\n\n" + formatPreparationSummary(result),
|
|
567
|
+
},
|
|
568
|
+
],
|
|
459
569
|
};
|
|
460
570
|
});
|
|
461
571
|
// Register execute_mcp_installation tool (local, no API key required)
|
|
462
572
|
server.registerTool(executeMCPInstallationTool.name, {
|
|
463
|
-
title:
|
|
573
|
+
title: "Execute MCP Installation",
|
|
464
574
|
description: executeMCPInstallationTool.description,
|
|
465
575
|
inputSchema: {
|
|
466
|
-
envMcpPath: z
|
|
576
|
+
envMcpPath: z
|
|
577
|
+
.string()
|
|
578
|
+
.optional()
|
|
579
|
+
.describe("Path to .env-mcp file (default: .env-mcp in current directory)"),
|
|
467
580
|
targetClient: z
|
|
468
|
-
.enum([
|
|
581
|
+
.enum([
|
|
582
|
+
"claude-code",
|
|
583
|
+
"claude-desktop",
|
|
584
|
+
"cursor",
|
|
585
|
+
"vscode",
|
|
586
|
+
"windsurf",
|
|
587
|
+
])
|
|
469
588
|
.optional()
|
|
470
|
-
.describe(
|
|
471
|
-
dryRun: z
|
|
589
|
+
.describe("Target IDE/client for installation (default: claude-code)"),
|
|
590
|
+
dryRun: z
|
|
591
|
+
.boolean()
|
|
592
|
+
.optional()
|
|
593
|
+
.describe("Only generate commands without marking ready to execute (default: false)"),
|
|
472
594
|
},
|
|
473
|
-
annotations: executeMcpInstallationAnnotations
|
|
595
|
+
annotations: executeMcpInstallationAnnotations,
|
|
474
596
|
}, async (args) => {
|
|
475
|
-
debug(
|
|
597
|
+
debug("execute_mcp_installation called", args);
|
|
476
598
|
const input = ExecuteMCPInstallationInputSchema.parse(args);
|
|
477
599
|
const result = await executeMCPInstallation(input);
|
|
478
600
|
return {
|
|
479
|
-
content: [{ type:
|
|
601
|
+
content: [{ type: "text", text: formatExecutionResult(result) }],
|
|
480
602
|
};
|
|
481
603
|
});
|
|
482
604
|
// ========================================================================
|
|
@@ -484,46 +606,64 @@ export function createServer() {
|
|
|
484
606
|
// ========================================================================
|
|
485
607
|
// Register check_mcp_compatibility tool (local, no API key required)
|
|
486
608
|
server.registerTool(checkCompatibilityToolDefinition.name, {
|
|
487
|
-
title:
|
|
609
|
+
title: "Check MCP Compatibility",
|
|
488
610
|
description: checkCompatibilityToolDefinition.description,
|
|
489
611
|
inputSchema: {
|
|
490
612
|
mcps: z
|
|
491
613
|
.array(z.string().min(1))
|
|
492
614
|
.min(1)
|
|
493
615
|
.max(20)
|
|
494
|
-
.describe(
|
|
616
|
+
.describe("Array of MCP server IDs to check compatibility between"),
|
|
495
617
|
},
|
|
496
|
-
annotations: checkCompatibilityAnnotations
|
|
618
|
+
annotations: checkCompatibilityAnnotations,
|
|
497
619
|
}, async (args) => {
|
|
498
|
-
debug(
|
|
620
|
+
debug("check_mcp_compatibility called", args);
|
|
499
621
|
const input = CheckCompatibilityInputSchema.parse(args);
|
|
500
622
|
const { text, data, isError } = executeCheckCompatibility(input);
|
|
501
623
|
return {
|
|
502
624
|
content: [
|
|
503
|
-
{ type:
|
|
504
|
-
{
|
|
625
|
+
{ type: "text", text },
|
|
626
|
+
{
|
|
627
|
+
type: "text",
|
|
628
|
+
text: `\n---\n\n**Structured Data:**\n\`\`\`json\n${JSON.stringify(data, null, 2)}\n\`\`\``,
|
|
629
|
+
},
|
|
505
630
|
],
|
|
506
|
-
isError
|
|
631
|
+
isError,
|
|
507
632
|
};
|
|
508
633
|
});
|
|
509
634
|
// Register get_workflow_guide tool (local, FREE, no API key required)
|
|
510
635
|
server.registerTool(getWorkflowGuideToolDefinition.name, {
|
|
511
|
-
title:
|
|
636
|
+
title: "Get Workflow Guide",
|
|
512
637
|
description: getWorkflowGuideToolDefinition.description,
|
|
513
638
|
inputSchema: {
|
|
514
|
-
current_goal: z
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
639
|
+
current_goal: z
|
|
640
|
+
.enum(WORKFLOW_GOALS)
|
|
641
|
+
.optional()
|
|
642
|
+
.describe("What the user is trying to accomplish"),
|
|
643
|
+
completed_tools: z
|
|
644
|
+
.array(z.string())
|
|
645
|
+
.optional()
|
|
646
|
+
.describe("Tools already called in this session"),
|
|
647
|
+
user_tier: z
|
|
648
|
+
.enum(USER_TIERS)
|
|
649
|
+
.optional()
|
|
650
|
+
.describe("User tier: free, pro, or unknown"),
|
|
651
|
+
known_constraints: z
|
|
652
|
+
.array(z.string())
|
|
653
|
+
.optional()
|
|
654
|
+
.describe("Constraints like must_use_postgresql"),
|
|
655
|
+
context: z
|
|
656
|
+
.enum(WORKFLOW_CONTEXTS)
|
|
657
|
+
.optional()
|
|
658
|
+
.describe("Client context for adapted snippets"),
|
|
519
659
|
},
|
|
520
|
-
annotations: getWorkflowGuideAnnotations
|
|
660
|
+
annotations: getWorkflowGuideAnnotations,
|
|
521
661
|
}, async (args) => {
|
|
522
|
-
debug(
|
|
662
|
+
debug("get_workflow_guide called", args);
|
|
523
663
|
const input = GetWorkflowGuideInputSchema.parse(args);
|
|
524
664
|
const { text } = executeGetWorkflowGuide(input);
|
|
525
665
|
return {
|
|
526
|
-
content: [{ type:
|
|
666
|
+
content: [{ type: "text", text }],
|
|
527
667
|
};
|
|
528
668
|
});
|
|
529
669
|
// ========================================================================
|
|
@@ -531,50 +671,60 @@ export function createServer() {
|
|
|
531
671
|
// ========================================================================
|
|
532
672
|
// Register estimate_project tool (API-based, requires API key with estimate:write)
|
|
533
673
|
server.registerTool(estimateProjectToolDefinition.name, {
|
|
534
|
-
title:
|
|
674
|
+
title: "Estimate Project",
|
|
535
675
|
description: estimateProjectToolDefinition.description,
|
|
536
676
|
inputSchema: {
|
|
537
677
|
specs: z
|
|
538
678
|
.string()
|
|
539
679
|
.min(100)
|
|
540
680
|
.max(10000)
|
|
541
|
-
.describe(
|
|
542
|
-
teamSize: z
|
|
681
|
+
.describe("Project specifications (min 100 chars, max 10,000)"),
|
|
682
|
+
teamSize: z
|
|
683
|
+
.number()
|
|
684
|
+
.min(1)
|
|
685
|
+
.max(100)
|
|
686
|
+
.optional()
|
|
687
|
+
.describe("Number of developers"),
|
|
543
688
|
seniorityLevel: z
|
|
544
|
-
.enum([
|
|
689
|
+
.enum(["junior", "mid", "senior", "expert"])
|
|
545
690
|
.optional()
|
|
546
|
-
.describe(
|
|
691
|
+
.describe("Average team seniority (default: mid)"),
|
|
547
692
|
region: z
|
|
548
|
-
.enum([
|
|
693
|
+
.enum(["france", "us", "uk", "remote-global"])
|
|
694
|
+
.optional()
|
|
695
|
+
.describe("Region for pricing (default: france)"),
|
|
696
|
+
includeMarket: z
|
|
697
|
+
.boolean()
|
|
549
698
|
.optional()
|
|
550
|
-
.describe(
|
|
551
|
-
includeMarket: z.boolean().optional().describe('Include market analysis (default: true)')
|
|
699
|
+
.describe("Include market analysis (default: true)"),
|
|
552
700
|
},
|
|
553
|
-
annotations: estimateProjectAnnotations
|
|
701
|
+
annotations: estimateProjectAnnotations,
|
|
554
702
|
}, async (args) => {
|
|
555
|
-
debug(
|
|
703
|
+
debug("estimate_project called", {
|
|
704
|
+
specsLength: args.specs?.length,
|
|
705
|
+
});
|
|
556
706
|
const input = EstimateProjectInputSchema.parse(args);
|
|
557
707
|
const { text, isError } = await executeEstimateProject(input);
|
|
558
708
|
return {
|
|
559
|
-
content: [{ type:
|
|
560
|
-
isError
|
|
709
|
+
content: [{ type: "text", text }],
|
|
710
|
+
isError,
|
|
561
711
|
};
|
|
562
712
|
});
|
|
563
713
|
// Register get_estimate_quota tool (API-based, requires API key)
|
|
564
714
|
server.registerTool(getEstimateQuotaToolDefinition.name, {
|
|
565
|
-
title:
|
|
715
|
+
title: "Get Estimate Quota",
|
|
566
716
|
description: getEstimateQuotaToolDefinition.description,
|
|
567
717
|
inputSchema: {},
|
|
568
|
-
annotations: getEstimateQuotaAnnotations
|
|
718
|
+
annotations: getEstimateQuotaAnnotations,
|
|
569
719
|
}, async () => {
|
|
570
|
-
debug(
|
|
720
|
+
debug("get_estimate_quota called");
|
|
571
721
|
const { text, isError } = await executeGetEstimateQuota({});
|
|
572
722
|
return {
|
|
573
|
-
content: [{ type:
|
|
574
|
-
isError
|
|
723
|
+
content: [{ type: "text", text }],
|
|
724
|
+
isError,
|
|
575
725
|
};
|
|
576
726
|
});
|
|
577
|
-
info(
|
|
727
|
+
info("Registered 26 tools: list_technologies, analyze_tech, compare_techs, recommend_stack_demo, recommend_stack, get_blueprint, create_blueprint, setup_api_key, list_api_keys, revoke_api_key, create_api_key, create_audit, get_audit, list_audits, compare_audits, get_audit_quota, get_migration_recommendation, import_better_t_stack, generate_mcp_kit, analyze_repo_mcps, prepare_mcp_installation, execute_mcp_installation, check_mcp_compatibility, get_workflow_guide, estimate_project, get_estimate_quota");
|
|
578
728
|
return server;
|
|
579
729
|
}
|
|
580
730
|
// ============================================================================
|
|
@@ -585,102 +735,102 @@ export function createServer() {
|
|
|
585
735
|
*/
|
|
586
736
|
function formatAnalysisResult(result) {
|
|
587
737
|
const lines = [];
|
|
588
|
-
lines.push(
|
|
738
|
+
lines.push("# Repository Analysis\n");
|
|
589
739
|
// Detected Stack
|
|
590
|
-
lines.push(
|
|
740
|
+
lines.push("## Detected Technologies\n");
|
|
591
741
|
const stackItems = [
|
|
592
742
|
result.detectedStack.frontend &&
|
|
593
|
-
`- **Frontend**: ${result.detectedStack.frontend.name}${result.detectedStack.frontend.version ? ` (${result.detectedStack.frontend.version})` :
|
|
743
|
+
`- **Frontend**: ${result.detectedStack.frontend.name}${result.detectedStack.frontend.version ? ` (${result.detectedStack.frontend.version})` : ""}`,
|
|
594
744
|
result.detectedStack.backend &&
|
|
595
|
-
`- **Backend**: ${result.detectedStack.backend.name}${result.detectedStack.backend.version ? ` (${result.detectedStack.backend.version})` :
|
|
745
|
+
`- **Backend**: ${result.detectedStack.backend.name}${result.detectedStack.backend.version ? ` (${result.detectedStack.backend.version})` : ""}`,
|
|
596
746
|
result.detectedStack.database &&
|
|
597
|
-
`- **Database**: ${result.detectedStack.database.name}${result.detectedStack.database.version ? ` (${result.detectedStack.database.version})` :
|
|
747
|
+
`- **Database**: ${result.detectedStack.database.name}${result.detectedStack.database.version ? ` (${result.detectedStack.database.version})` : ""}`,
|
|
598
748
|
result.detectedStack.orm &&
|
|
599
|
-
`- **ORM**: ${result.detectedStack.orm.name}${result.detectedStack.orm.version ? ` (${result.detectedStack.orm.version})` :
|
|
749
|
+
`- **ORM**: ${result.detectedStack.orm.name}${result.detectedStack.orm.version ? ` (${result.detectedStack.orm.version})` : ""}`,
|
|
600
750
|
result.detectedStack.auth &&
|
|
601
|
-
`- **Auth**: ${result.detectedStack.auth.name}${result.detectedStack.auth.version ? ` (${result.detectedStack.auth.version})` :
|
|
751
|
+
`- **Auth**: ${result.detectedStack.auth.name}${result.detectedStack.auth.version ? ` (${result.detectedStack.auth.version})` : ""}`,
|
|
602
752
|
result.detectedStack.hosting &&
|
|
603
|
-
`- **Hosting**: ${result.detectedStack.hosting.name}${result.detectedStack.hosting.version ? ` (${result.detectedStack.hosting.version})` :
|
|
753
|
+
`- **Hosting**: ${result.detectedStack.hosting.name}${result.detectedStack.hosting.version ? ` (${result.detectedStack.hosting.version})` : ""}`,
|
|
604
754
|
result.detectedStack.payments &&
|
|
605
|
-
`- **Payments**: ${result.detectedStack.payments.name}${result.detectedStack.payments.version ? ` (${result.detectedStack.payments.version})` :
|
|
755
|
+
`- **Payments**: ${result.detectedStack.payments.name}${result.detectedStack.payments.version ? ` (${result.detectedStack.payments.version})` : ""}`,
|
|
606
756
|
].filter((item) => Boolean(item));
|
|
607
757
|
if (stackItems.length > 0) {
|
|
608
758
|
lines.push(...stackItems);
|
|
609
759
|
}
|
|
610
760
|
else {
|
|
611
|
-
lines.push(
|
|
761
|
+
lines.push("_No technologies detected from project files._");
|
|
612
762
|
}
|
|
613
763
|
if (result.detectedStack.services.length > 0) {
|
|
614
|
-
lines.push(
|
|
764
|
+
lines.push("\n**Services**:");
|
|
615
765
|
for (const service of result.detectedStack.services) {
|
|
616
766
|
lines.push(`- ${service.name}`);
|
|
617
767
|
}
|
|
618
768
|
}
|
|
619
|
-
lines.push(
|
|
769
|
+
lines.push("");
|
|
620
770
|
// Files Analyzed
|
|
621
|
-
lines.push(
|
|
771
|
+
lines.push("## Files Analyzed\n");
|
|
622
772
|
if (result.metadata.filesAnalyzed.length > 0) {
|
|
623
|
-
lines.push(result.metadata.filesAnalyzed.map((f) => `- \`${f}\``).join(
|
|
773
|
+
lines.push(result.metadata.filesAnalyzed.map((f) => `- \`${f}\``).join("\n"));
|
|
624
774
|
}
|
|
625
775
|
else {
|
|
626
|
-
lines.push(
|
|
776
|
+
lines.push("_No recognized configuration files found._");
|
|
627
777
|
}
|
|
628
|
-
lines.push(
|
|
778
|
+
lines.push("");
|
|
629
779
|
// Installed MCPs
|
|
630
780
|
if (result.installedMcps.length > 0) {
|
|
631
|
-
lines.push(
|
|
632
|
-
lines.push(result.installedMcps.map((m) => `- ${m}`).join(
|
|
633
|
-
lines.push(
|
|
781
|
+
lines.push("## Already Installed MCPs\n");
|
|
782
|
+
lines.push(result.installedMcps.map((m) => `- ${m}`).join("\n"));
|
|
783
|
+
lines.push("");
|
|
634
784
|
}
|
|
635
785
|
// Recommended MCPs
|
|
636
|
-
lines.push(
|
|
786
|
+
lines.push("## Recommended MCPs\n");
|
|
637
787
|
if (result.recommendedMcps.length === 0) {
|
|
638
|
-
lines.push(
|
|
788
|
+
lines.push("_No additional MCPs recommended. You have everything you need!_");
|
|
639
789
|
}
|
|
640
790
|
else {
|
|
641
791
|
// Group by priority
|
|
642
|
-
const highPriority = result.recommendedMcps.filter((m) => m.priority ===
|
|
643
|
-
const mediumPriority = result.recommendedMcps.filter((m) => m.priority ===
|
|
644
|
-
const lowPriority = result.recommendedMcps.filter((m) => m.priority ===
|
|
792
|
+
const highPriority = result.recommendedMcps.filter((m) => m.priority === "high");
|
|
793
|
+
const mediumPriority = result.recommendedMcps.filter((m) => m.priority === "medium");
|
|
794
|
+
const lowPriority = result.recommendedMcps.filter((m) => m.priority === "low");
|
|
645
795
|
if (highPriority.length > 0) {
|
|
646
|
-
lines.push(
|
|
796
|
+
lines.push("### High Priority\n");
|
|
647
797
|
for (const mcp of highPriority) {
|
|
648
798
|
lines.push(`**${mcp.name}** (\`${mcp.slug}\`)`);
|
|
649
799
|
lines.push(`- ${mcp.description}`);
|
|
650
800
|
lines.push(`- _Matched: ${mcp.matchedTech}_`);
|
|
651
|
-
lines.push(
|
|
801
|
+
lines.push("");
|
|
652
802
|
}
|
|
653
803
|
}
|
|
654
804
|
if (mediumPriority.length > 0) {
|
|
655
|
-
lines.push(
|
|
805
|
+
lines.push("### Medium Priority\n");
|
|
656
806
|
for (const mcp of mediumPriority) {
|
|
657
807
|
lines.push(`**${mcp.name}** (\`${mcp.slug}\`)`);
|
|
658
808
|
lines.push(`- ${mcp.description}`);
|
|
659
809
|
lines.push(`- _Matched: ${mcp.matchedTech}_`);
|
|
660
|
-
lines.push(
|
|
810
|
+
lines.push("");
|
|
661
811
|
}
|
|
662
812
|
}
|
|
663
813
|
if (lowPriority.length > 0) {
|
|
664
|
-
lines.push(
|
|
814
|
+
lines.push("### Low Priority\n");
|
|
665
815
|
for (const mcp of lowPriority) {
|
|
666
816
|
lines.push(`**${mcp.name}** (\`${mcp.slug}\`)`);
|
|
667
817
|
lines.push(`- ${mcp.description}`);
|
|
668
818
|
lines.push(`- _Matched: ${mcp.matchedTech}_`);
|
|
669
|
-
lines.push(
|
|
819
|
+
lines.push("");
|
|
670
820
|
}
|
|
671
821
|
}
|
|
672
822
|
}
|
|
673
823
|
// Quick Install
|
|
674
824
|
if (result.recommendedMcps.length > 0) {
|
|
675
|
-
lines.push(
|
|
676
|
-
lines.push(
|
|
677
|
-
lines.push(
|
|
825
|
+
lines.push("## Quick Install\n");
|
|
826
|
+
lines.push("Add to your Claude Desktop config (`claude_desktop_config.json`):\n");
|
|
827
|
+
lines.push("```json");
|
|
678
828
|
lines.push(JSON.stringify(result.installConfig.claudeDesktop, null, 2));
|
|
679
|
-
lines.push(
|
|
829
|
+
lines.push("```\n");
|
|
680
830
|
}
|
|
681
831
|
// Metadata
|
|
682
832
|
lines.push(`---\n_Analysis completed: ${result.metadata.analysisDate}_`);
|
|
683
|
-
return lines.join(
|
|
833
|
+
return lines.join("\n");
|
|
684
834
|
}
|
|
685
835
|
/**
|
|
686
836
|
* Format prepare_mcp_installation result summary.
|
|
@@ -689,44 +839,44 @@ function formatPreparationSummary(result) {
|
|
|
689
839
|
const lines = [];
|
|
690
840
|
// MCPs to install grouped by priority
|
|
691
841
|
if (result.mcpsToInstall.length > 0) {
|
|
692
|
-
lines.push(
|
|
693
|
-
const highPriority = result.mcpsToInstall.filter((m) => m.priority ===
|
|
694
|
-
const mediumPriority = result.mcpsToInstall.filter((m) => m.priority ===
|
|
695
|
-
const lowPriority = result.mcpsToInstall.filter((m) => m.priority ===
|
|
842
|
+
lines.push("## MCPs to Install\n");
|
|
843
|
+
const highPriority = result.mcpsToInstall.filter((m) => m.priority === "high");
|
|
844
|
+
const mediumPriority = result.mcpsToInstall.filter((m) => m.priority === "medium");
|
|
845
|
+
const lowPriority = result.mcpsToInstall.filter((m) => m.priority === "low");
|
|
696
846
|
if (highPriority.length > 0) {
|
|
697
|
-
lines.push(
|
|
847
|
+
lines.push("### 🔴 High Priority");
|
|
698
848
|
for (const mcp of highPriority) {
|
|
699
|
-
const requiredVars = mcp.envVars.filter((v) => v.requirement ===
|
|
849
|
+
const requiredVars = mcp.envVars.filter((v) => v.requirement === "required").length;
|
|
700
850
|
lines.push(`- **${mcp.name}** (${requiredVars} required vars)`);
|
|
701
851
|
}
|
|
702
|
-
lines.push(
|
|
852
|
+
lines.push("");
|
|
703
853
|
}
|
|
704
854
|
if (mediumPriority.length > 0) {
|
|
705
|
-
lines.push(
|
|
855
|
+
lines.push("### 🟡 Medium Priority");
|
|
706
856
|
for (const mcp of mediumPriority) {
|
|
707
|
-
const requiredVars = mcp.envVars.filter((v) => v.requirement ===
|
|
857
|
+
const requiredVars = mcp.envVars.filter((v) => v.requirement === "required").length;
|
|
708
858
|
lines.push(`- **${mcp.name}** (${requiredVars} required vars)`);
|
|
709
859
|
}
|
|
710
|
-
lines.push(
|
|
860
|
+
lines.push("");
|
|
711
861
|
}
|
|
712
862
|
if (lowPriority.length > 0) {
|
|
713
|
-
lines.push(
|
|
863
|
+
lines.push("### 🟢 Low Priority");
|
|
714
864
|
for (const mcp of lowPriority) {
|
|
715
|
-
const requiredVars = mcp.envVars.filter((v) => v.requirement ===
|
|
865
|
+
const requiredVars = mcp.envVars.filter((v) => v.requirement === "required").length;
|
|
716
866
|
lines.push(`- **${mcp.name}** (${requiredVars} required vars)`);
|
|
717
867
|
}
|
|
718
|
-
lines.push(
|
|
868
|
+
lines.push("");
|
|
719
869
|
}
|
|
720
870
|
}
|
|
721
871
|
// Already installed
|
|
722
872
|
if (result.installedMcps.length > 0) {
|
|
723
|
-
lines.push(
|
|
873
|
+
lines.push("## Already Installed");
|
|
724
874
|
for (const mcp of result.installedMcps) {
|
|
725
875
|
lines.push(`- ✅ ${mcp}`);
|
|
726
876
|
}
|
|
727
|
-
lines.push(
|
|
877
|
+
lines.push("");
|
|
728
878
|
}
|
|
729
|
-
return lines.join(
|
|
879
|
+
return lines.join("\n");
|
|
730
880
|
}
|
|
731
881
|
/**
|
|
732
882
|
* Format execute_mcp_installation result.
|
|
@@ -734,33 +884,33 @@ function formatPreparationSummary(result) {
|
|
|
734
884
|
function formatExecutionResult(result) {
|
|
735
885
|
const lines = [];
|
|
736
886
|
lines.push(result.message);
|
|
737
|
-
lines.push(
|
|
887
|
+
lines.push("");
|
|
738
888
|
// Show aggregate command for Claude Code
|
|
739
889
|
if (result.aggregateCommand) {
|
|
740
|
-
lines.push(
|
|
741
|
-
lines.push(
|
|
742
|
-
lines.push(
|
|
743
|
-
lines.push(
|
|
890
|
+
lines.push("---\n");
|
|
891
|
+
lines.push("## Claude Code Installation\n");
|
|
892
|
+
lines.push("Run this command to install all ready MCPs:\n");
|
|
893
|
+
lines.push("```bash");
|
|
744
894
|
lines.push(result.aggregateCommand);
|
|
745
|
-
lines.push(
|
|
895
|
+
lines.push("```\n");
|
|
746
896
|
}
|
|
747
897
|
// Show JSON config for other clients
|
|
748
898
|
if (result.aggregateConfig && !result.aggregateCommand) {
|
|
749
|
-
lines.push(
|
|
750
|
-
lines.push(
|
|
751
|
-
lines.push(
|
|
752
|
-
lines.push(
|
|
899
|
+
lines.push("---\n");
|
|
900
|
+
lines.push("## JSON Configuration\n");
|
|
901
|
+
lines.push("Add this to your MCP configuration file:\n");
|
|
902
|
+
lines.push("```json");
|
|
753
903
|
lines.push(JSON.stringify(result.aggregateConfig, null, 2));
|
|
754
|
-
lines.push(
|
|
904
|
+
lines.push("```\n");
|
|
755
905
|
}
|
|
756
906
|
// Post-install instructions
|
|
757
907
|
if (result.postInstallInstructions.length > 0) {
|
|
758
|
-
lines.push(
|
|
759
|
-
lines.push(
|
|
908
|
+
lines.push("---\n");
|
|
909
|
+
lines.push("## Post-Installation\n");
|
|
760
910
|
for (const instruction of result.postInstallInstructions) {
|
|
761
911
|
lines.push(instruction);
|
|
762
912
|
}
|
|
763
913
|
}
|
|
764
|
-
return lines.join(
|
|
914
|
+
return lines.join("\n");
|
|
765
915
|
}
|
|
766
916
|
//# sourceMappingURL=server.js.map
|