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