@stacksfinder/mcp-server 1.0.2 → 1.2.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/LICENSE +21 -0
- package/README.md +414 -262
- package/dist/compatibility/index.d.ts +11 -0
- package/dist/compatibility/index.d.ts.map +1 -0
- package/dist/compatibility/index.js +13 -0
- package/dist/compatibility/index.js.map +1 -0
- package/dist/compatibility/rules.d.ts +29 -0
- package/dist/compatibility/rules.d.ts.map +1 -0
- package/dist/compatibility/rules.js +419 -0
- package/dist/compatibility/rules.js.map +1 -0
- package/dist/compatibility/scoring.d.ts +54 -0
- package/dist/compatibility/scoring.d.ts.map +1 -0
- package/dist/compatibility/scoring.js +209 -0
- package/dist/compatibility/scoring.js.map +1 -0
- package/dist/compatibility/types.d.ts +176 -0
- package/dist/compatibility/types.d.ts.map +1 -0
- package/dist/compatibility/types.js +26 -0
- package/dist/compatibility/types.js.map +1 -0
- package/dist/compatibility/utils.d.ts +82 -0
- package/dist/compatibility/utils.d.ts.map +1 -0
- package/dist/compatibility/utils.js +269 -0
- package/dist/compatibility/utils.js.map +1 -0
- package/dist/data/357/200/242/357/200/212cp H:bac_/303/240_guigui_v2stack_finderpackagesmcp-serversrcdatacompatibility_matrix.json H:bac_/303/240_guigui_v2stack_finderpackagesmcp-serverdistdata/357/200/242" +226 -0
- package/dist/http.d.ts +7 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +69 -0
- package/dist/http.js.map +1 -0
- package/dist/lib/mcp-compatibility/index.d.ts +33 -0
- package/dist/lib/mcp-compatibility/index.d.ts.map +1 -0
- package/dist/lib/mcp-compatibility/index.js +35 -0
- package/dist/lib/mcp-compatibility/index.js.map +1 -0
- package/dist/lib/mcp-compatibility/rules.d.ts +29 -0
- package/dist/lib/mcp-compatibility/rules.d.ts.map +1 -0
- package/dist/lib/mcp-compatibility/rules.js +419 -0
- package/dist/lib/mcp-compatibility/rules.js.map +1 -0
- package/dist/lib/mcp-compatibility/scoring.d.ts +54 -0
- package/dist/lib/mcp-compatibility/scoring.d.ts.map +1 -0
- package/dist/lib/mcp-compatibility/scoring.js +209 -0
- package/dist/lib/mcp-compatibility/scoring.js.map +1 -0
- package/dist/lib/mcp-compatibility/types.d.ts +176 -0
- package/dist/lib/mcp-compatibility/types.d.ts.map +1 -0
- package/dist/lib/mcp-compatibility/types.js +26 -0
- package/dist/lib/mcp-compatibility/types.js.map +1 -0
- package/dist/lib/mcp-compatibility/utils.d.ts +82 -0
- package/dist/lib/mcp-compatibility/utils.d.ts.map +1 -0
- package/dist/lib/mcp-compatibility/utils.js +269 -0
- package/dist/lib/mcp-compatibility/utils.js.map +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +404 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/audit.d.ts +246 -0
- package/dist/tools/audit.d.ts.map +1 -0
- package/dist/tools/audit.js +559 -0
- package/dist/tools/audit.js.map +1 -0
- package/dist/tools/check-compatibility.d.ts +43 -0
- package/dist/tools/check-compatibility.d.ts.map +1 -0
- package/dist/tools/check-compatibility.js +133 -0
- package/dist/tools/check-compatibility.js.map +1 -0
- package/dist/tools/project-kit/analyze-repo.d.ts +50 -0
- package/dist/tools/project-kit/analyze-repo.d.ts.map +1 -0
- package/dist/tools/project-kit/analyze-repo.js +456 -0
- package/dist/tools/project-kit/analyze-repo.js.map +1 -0
- package/dist/tools/project-kit/detect-stack.d.ts +16 -0
- package/dist/tools/project-kit/detect-stack.d.ts.map +1 -0
- package/dist/tools/project-kit/detect-stack.js +572 -0
- package/dist/tools/project-kit/detect-stack.js.map +1 -0
- package/dist/tools/project-kit/execute-installation.d.ts +50 -0
- package/dist/tools/project-kit/execute-installation.d.ts.map +1 -0
- package/dist/tools/project-kit/execute-installation.js +440 -0
- package/dist/tools/project-kit/execute-installation.js.map +1 -0
- package/dist/tools/project-kit/generate.d.ts +70 -0
- package/dist/tools/project-kit/generate.d.ts.map +1 -0
- package/dist/tools/project-kit/generate.js +455 -0
- package/dist/tools/project-kit/generate.js.map +1 -0
- package/dist/tools/project-kit/index.d.ts +18 -0
- package/dist/tools/project-kit/index.d.ts.map +1 -0
- package/dist/tools/project-kit/index.js +21 -0
- package/dist/tools/project-kit/index.js.map +1 -0
- package/dist/tools/project-kit/installation-types.d.ts +147 -0
- package/dist/tools/project-kit/installation-types.d.ts.map +1 -0
- package/dist/tools/project-kit/installation-types.js +491 -0
- package/dist/tools/project-kit/installation-types.js.map +1 -0
- package/dist/tools/project-kit/match-mcps.d.ts +67 -0
- package/dist/tools/project-kit/match-mcps.d.ts.map +1 -0
- package/dist/tools/project-kit/match-mcps.js +497 -0
- package/dist/tools/project-kit/match-mcps.js.map +1 -0
- package/dist/tools/project-kit/prepare-installation.d.ts +54 -0
- package/dist/tools/project-kit/prepare-installation.d.ts.map +1 -0
- package/dist/tools/project-kit/prepare-installation.js +382 -0
- package/dist/tools/project-kit/prepare-installation.js.map +1 -0
- package/dist/tools/project-kit/types.d.ts +200 -0
- package/dist/tools/project-kit/types.d.ts.map +1 -0
- package/dist/tools/project-kit/types.js +76 -0
- package/dist/tools/project-kit/types.js.map +1 -0
- package/dist/tools/recommend.d.ts.map +1 -1
- package/dist/tools/recommend.js +9 -4
- package/dist/tools/recommend.js.map +1 -1
- package/package.json +8 -3
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Compatibility Check Tool
|
|
3
|
+
*
|
|
4
|
+
* Free tier tool that checks compatibility between a set of MCP servers.
|
|
5
|
+
* Detects conflicts, redundancies, and synergies.
|
|
6
|
+
* Returns both markdown text and structured JSON data.
|
|
7
|
+
*/
|
|
8
|
+
import { z } from 'zod';
|
|
9
|
+
import { initRulesIndex, getAllRules, generateReport, formatReportAsMarkdown, getReportSummaryLine, CURATED_MCPS, } from '../lib/mcp-compatibility/index.js';
|
|
10
|
+
// ============================================
|
|
11
|
+
// Input Schema
|
|
12
|
+
// ============================================
|
|
13
|
+
export const CheckCompatibilityInputSchema = z.object({
|
|
14
|
+
mcps: z
|
|
15
|
+
.array(z.string().min(1))
|
|
16
|
+
.min(1)
|
|
17
|
+
.max(20)
|
|
18
|
+
.describe('Array of MCP server IDs to check compatibility between'),
|
|
19
|
+
});
|
|
20
|
+
// ============================================
|
|
21
|
+
// Tool Definition
|
|
22
|
+
// ============================================
|
|
23
|
+
export const checkCompatibilityToolDefinition = {
|
|
24
|
+
name: 'check_mcp_compatibility',
|
|
25
|
+
description: `Check compatibility between MCP servers. Detects conflicts (e.g., two database providers), redundancies (e.g., two ORMs), and synergies (e.g., GitHub + Vercel).
|
|
26
|
+
|
|
27
|
+
Returns a health score (0-100) with grade (A/B/C/D) and detailed breakdown.
|
|
28
|
+
|
|
29
|
+
**Examples:**
|
|
30
|
+
- Check database compatibility: \`["supabase-mcp", "neon-mcp"]\` → conflict detected
|
|
31
|
+
- Check ORM redundancy: \`["prisma-mcp", "drizzle-mcp"]\` → redundancy warning
|
|
32
|
+
- Check synergies: \`["stripe-mcp", "resend-mcp"]\` → synergy detected
|
|
33
|
+
|
|
34
|
+
**Supported MCP IDs include:**
|
|
35
|
+
${CURATED_MCPS.slice(0, 10).map((mcp) => `- ${mcp}`).join('\n')}
|
|
36
|
+
...and more.
|
|
37
|
+
|
|
38
|
+
**Aliases supported:**
|
|
39
|
+
- "supabase" → "supabase-mcp"
|
|
40
|
+
- "@neondatabase/mcp" → "neon-mcp"
|
|
41
|
+
- "stripe" → "stripe-mcp"`,
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: 'object',
|
|
44
|
+
properties: {
|
|
45
|
+
mcps: {
|
|
46
|
+
type: 'array',
|
|
47
|
+
items: { type: 'string' },
|
|
48
|
+
minItems: 1,
|
|
49
|
+
maxItems: 20,
|
|
50
|
+
description: 'Array of MCP server IDs to check compatibility between',
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
required: ['mcps'],
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
// ============================================
|
|
57
|
+
// Initialize Rules Index
|
|
58
|
+
// ============================================
|
|
59
|
+
let rulesInitialized = false;
|
|
60
|
+
function ensureRulesInitialized() {
|
|
61
|
+
if (!rulesInitialized) {
|
|
62
|
+
initRulesIndex(getAllRules());
|
|
63
|
+
rulesInitialized = true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ============================================
|
|
67
|
+
// Execute Function
|
|
68
|
+
// ============================================
|
|
69
|
+
export function executeCheckCompatibility(input) {
|
|
70
|
+
try {
|
|
71
|
+
// Validate input
|
|
72
|
+
const parsed = CheckCompatibilityInputSchema.safeParse(input);
|
|
73
|
+
if (!parsed.success) {
|
|
74
|
+
return {
|
|
75
|
+
text: `Invalid input: ${parsed.error.message}`,
|
|
76
|
+
data: {
|
|
77
|
+
analyzedMcps: [],
|
|
78
|
+
summary: {
|
|
79
|
+
total: 0,
|
|
80
|
+
conflicts: 0,
|
|
81
|
+
redundancies: 0,
|
|
82
|
+
synergies: 0,
|
|
83
|
+
score: 0,
|
|
84
|
+
grade: 'D',
|
|
85
|
+
},
|
|
86
|
+
conflicts: [],
|
|
87
|
+
redundancies: [],
|
|
88
|
+
synergies: [],
|
|
89
|
+
suggestions: [],
|
|
90
|
+
},
|
|
91
|
+
isError: true,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const { mcps } = parsed.data;
|
|
95
|
+
// Initialize rules index
|
|
96
|
+
ensureRulesInitialized();
|
|
97
|
+
// Generate compatibility report
|
|
98
|
+
const report = generateReport(mcps, getAllRules());
|
|
99
|
+
// Format as markdown
|
|
100
|
+
const markdown = formatReportAsMarkdown(report);
|
|
101
|
+
// Add summary line at the top
|
|
102
|
+
const summaryLine = getReportSummaryLine(report);
|
|
103
|
+
const text = `${summaryLine}\n\n${markdown}`;
|
|
104
|
+
return {
|
|
105
|
+
text,
|
|
106
|
+
data: report,
|
|
107
|
+
isError: false,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
112
|
+
return {
|
|
113
|
+
text: `Error checking compatibility: ${errorMessage}`,
|
|
114
|
+
data: {
|
|
115
|
+
analyzedMcps: [],
|
|
116
|
+
summary: {
|
|
117
|
+
total: 0,
|
|
118
|
+
conflicts: 0,
|
|
119
|
+
redundancies: 0,
|
|
120
|
+
synergies: 0,
|
|
121
|
+
score: 0,
|
|
122
|
+
grade: 'D',
|
|
123
|
+
},
|
|
124
|
+
conflicts: [],
|
|
125
|
+
redundancies: [],
|
|
126
|
+
synergies: [],
|
|
127
|
+
suggestions: [],
|
|
128
|
+
},
|
|
129
|
+
isError: true,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=check-compatibility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check-compatibility.js","sourceRoot":"","sources":["../../src/tools/check-compatibility.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* analyze_repo_mcps Tool
|
|
3
|
+
*
|
|
4
|
+
* Analyzes a repository to detect the tech stack and recommend
|
|
5
|
+
* appropriate MCP servers based on the detected technologies.
|
|
6
|
+
*/
|
|
7
|
+
import type { AnalyzeRepoMCPsInput, AnalyzeRepoMCPsOutput } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Analyze repository and recommend MCPs.
|
|
10
|
+
*/
|
|
11
|
+
export declare function analyzeRepo(input: AnalyzeRepoMCPsInput): Promise<AnalyzeRepoMCPsOutput>;
|
|
12
|
+
/**
|
|
13
|
+
* Tool definition for MCP server registration.
|
|
14
|
+
*/
|
|
15
|
+
export declare const analyzeRepoMcpsTool: {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
inputSchema: {
|
|
19
|
+
type: string;
|
|
20
|
+
properties: {
|
|
21
|
+
includeInstalled: {
|
|
22
|
+
type: string;
|
|
23
|
+
description: string;
|
|
24
|
+
default: boolean;
|
|
25
|
+
};
|
|
26
|
+
mcpConfigPath: {
|
|
27
|
+
type: string;
|
|
28
|
+
description: string;
|
|
29
|
+
};
|
|
30
|
+
workspaceRoot: {
|
|
31
|
+
type: string;
|
|
32
|
+
description: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
handler: (params: unknown) => Promise<{
|
|
37
|
+
content: {
|
|
38
|
+
type: string;
|
|
39
|
+
text: string;
|
|
40
|
+
}[];
|
|
41
|
+
isError?: undefined;
|
|
42
|
+
} | {
|
|
43
|
+
content: {
|
|
44
|
+
type: string;
|
|
45
|
+
text: string;
|
|
46
|
+
}[];
|
|
47
|
+
isError: boolean;
|
|
48
|
+
}>;
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=analyze-repo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-repo.d.ts","sourceRoot":"","sources":["../../../src/tools/project-kit/analyze-repo.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACX,oBAAoB,EACpB,qBAAqB,EAIrB,MAAM,YAAY,CAAC;AAyKpB;;GAEG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAqG7F;AAMD;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;sBAkCP,OAAO;;;;;;;;;;;;;CAiC/B,CAAC"}
|
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* analyze_repo_mcps Tool
|
|
3
|
+
*
|
|
4
|
+
* Analyzes a repository to detect the tech stack and recommend
|
|
5
|
+
* appropriate MCP servers based on the detected technologies.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'fs/promises';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import * as os from 'os';
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { AnalyzeRepoMCPsInputSchema } from './types.js';
|
|
12
|
+
import { detectStackFromFiles } from './detect-stack.js';
|
|
13
|
+
import { matchMCPsForStack, generateInstallConfig } from './match-mcps.js';
|
|
14
|
+
import { debug, info, error } from '../../utils/logger.js';
|
|
15
|
+
import { initRulesIndex, getAllRules, generateReport, findRule, canonicalizeMcpId } from '../../lib/mcp-compatibility/index.js';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// INSTALLED MCP DETECTION
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Common locations for MCP configuration files.
|
|
21
|
+
*/
|
|
22
|
+
const MCP_CONFIG_LOCATIONS = [
|
|
23
|
+
// Claude Desktop (macOS)
|
|
24
|
+
'~/Library/Application Support/Claude/claude_desktop_config.json',
|
|
25
|
+
// Claude Desktop (Windows)
|
|
26
|
+
'%APPDATA%/Claude/claude_desktop_config.json',
|
|
27
|
+
// Claude Desktop (Linux)
|
|
28
|
+
'~/.config/claude/claude_desktop_config.json',
|
|
29
|
+
// Cursor
|
|
30
|
+
'.cursor/mcp.json',
|
|
31
|
+
// VS Code
|
|
32
|
+
'.vscode/mcp.json',
|
|
33
|
+
// Project-local
|
|
34
|
+
'mcp.json',
|
|
35
|
+
'.mcp.json'
|
|
36
|
+
];
|
|
37
|
+
/**
|
|
38
|
+
* Expand path with environment variables and home directory.
|
|
39
|
+
*/
|
|
40
|
+
function expandPath(p) {
|
|
41
|
+
// Expand home directory
|
|
42
|
+
if (p.startsWith('~/')) {
|
|
43
|
+
p = path.join(os.homedir(), p.slice(2));
|
|
44
|
+
}
|
|
45
|
+
// Expand environment variables (Windows style)
|
|
46
|
+
p = p.replace(/%([^%]+)%/g, (_, envVar) => process.env[envVar] || '');
|
|
47
|
+
return p;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Parse MCP config file and extract installed server slugs.
|
|
51
|
+
*/
|
|
52
|
+
async function parseConfigFile(configPath) {
|
|
53
|
+
try {
|
|
54
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
55
|
+
const config = JSON.parse(content);
|
|
56
|
+
const servers = [];
|
|
57
|
+
// Handle mcpServers object format
|
|
58
|
+
if (config.mcpServers && typeof config.mcpServers === 'object') {
|
|
59
|
+
servers.push(...Object.keys(config.mcpServers));
|
|
60
|
+
}
|
|
61
|
+
// Handle servers array format
|
|
62
|
+
if (Array.isArray(config.servers)) {
|
|
63
|
+
for (const server of config.servers) {
|
|
64
|
+
if (server.name) {
|
|
65
|
+
servers.push(server.name);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return servers;
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Detect installed MCPs from configuration files.
|
|
77
|
+
*/
|
|
78
|
+
async function getInstalledMCPs(workspaceRoot, customConfigPath) {
|
|
79
|
+
const installedMcps = new Set();
|
|
80
|
+
// Check custom config path first
|
|
81
|
+
if (customConfigPath) {
|
|
82
|
+
const servers = await parseConfigFile(path.resolve(workspaceRoot, customConfigPath));
|
|
83
|
+
servers.forEach((s) => installedMcps.add(s));
|
|
84
|
+
}
|
|
85
|
+
// Check all common locations
|
|
86
|
+
for (const location of MCP_CONFIG_LOCATIONS) {
|
|
87
|
+
let configPath;
|
|
88
|
+
if (location.startsWith('~') || location.includes('%')) {
|
|
89
|
+
// Absolute/home paths
|
|
90
|
+
configPath = expandPath(location);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
// Relative to workspace
|
|
94
|
+
configPath = path.join(workspaceRoot, location);
|
|
95
|
+
}
|
|
96
|
+
const servers = await parseConfigFile(configPath);
|
|
97
|
+
servers.forEach((s) => installedMcps.add(s));
|
|
98
|
+
}
|
|
99
|
+
debug(`Found ${installedMcps.size} installed MCPs`);
|
|
100
|
+
return Array.from(installedMcps);
|
|
101
|
+
}
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// COMPATIBILITY HELPERS
|
|
104
|
+
// ============================================================================
|
|
105
|
+
let rulesInitialized = false;
|
|
106
|
+
/**
|
|
107
|
+
* Ensure rules index is initialized.
|
|
108
|
+
*/
|
|
109
|
+
function ensureRulesInitialized() {
|
|
110
|
+
if (!rulesInitialized) {
|
|
111
|
+
initRulesIndex(getAllRules());
|
|
112
|
+
rulesInitialized = true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Convert CompatibilityReport to MCPCompatibilityResult.
|
|
117
|
+
*/
|
|
118
|
+
function convertToCompatibilityResult(report) {
|
|
119
|
+
return {
|
|
120
|
+
score: report.summary.score,
|
|
121
|
+
grade: report.summary.grade,
|
|
122
|
+
conflicts: report.conflicts.map((c) => ({
|
|
123
|
+
mcpA: c.rule.mcpA,
|
|
124
|
+
mcpB: c.rule.mcpB,
|
|
125
|
+
reason: c.rule.reason,
|
|
126
|
+
severity: c.rule.severity
|
|
127
|
+
})),
|
|
128
|
+
redundancies: report.redundancies.map((r) => ({
|
|
129
|
+
mcpA: r.rule.mcpA,
|
|
130
|
+
mcpB: r.rule.mcpB,
|
|
131
|
+
reason: r.rule.reason,
|
|
132
|
+
severity: r.rule.severity
|
|
133
|
+
})),
|
|
134
|
+
synergies: report.synergies.map((s) => ({
|
|
135
|
+
mcpA: s.rule.mcpA,
|
|
136
|
+
mcpB: s.rule.mcpB,
|
|
137
|
+
reason: s.rule.reason
|
|
138
|
+
})),
|
|
139
|
+
suggestions: report.suggestions.map((s) => ({
|
|
140
|
+
mcp: s.mcp,
|
|
141
|
+
reason: s.reason,
|
|
142
|
+
basedOn: s.basedOn
|
|
143
|
+
}))
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// ============================================================================
|
|
147
|
+
// TOOL IMPLEMENTATION
|
|
148
|
+
// ============================================================================
|
|
149
|
+
/**
|
|
150
|
+
* Analyze repository and recommend MCPs.
|
|
151
|
+
*/
|
|
152
|
+
export async function analyzeRepo(input) {
|
|
153
|
+
const workspaceRoot = input.workspaceRoot || process.cwd();
|
|
154
|
+
info(`Analyzing repository at: ${workspaceRoot}`);
|
|
155
|
+
// Initialize compatibility rules
|
|
156
|
+
ensureRulesInitialized();
|
|
157
|
+
// Step 1: Detect installed MCPs
|
|
158
|
+
const installedMcps = await getInstalledMCPs(workspaceRoot, input.mcpConfigPath);
|
|
159
|
+
// Step 2: Detect stack from files
|
|
160
|
+
const { stack: detectedStack, filesAnalyzed } = await detectStackFromFiles(workspaceRoot);
|
|
161
|
+
// Log detection summary
|
|
162
|
+
const stackSummary = [
|
|
163
|
+
detectedStack.frontend && `frontend: ${detectedStack.frontend.name}`,
|
|
164
|
+
detectedStack.backend && `backend: ${detectedStack.backend.name}`,
|
|
165
|
+
detectedStack.database && `database: ${detectedStack.database.name}`,
|
|
166
|
+
detectedStack.orm && `orm: ${detectedStack.orm.name}`,
|
|
167
|
+
detectedStack.auth && `auth: ${detectedStack.auth.name}`,
|
|
168
|
+
detectedStack.hosting && `hosting: ${detectedStack.hosting.name}`,
|
|
169
|
+
detectedStack.payments && `payments: ${detectedStack.payments.name}`,
|
|
170
|
+
detectedStack.services.length > 0 &&
|
|
171
|
+
`services: ${detectedStack.services.map((s) => s.name).join(', ')}`
|
|
172
|
+
]
|
|
173
|
+
.filter(Boolean)
|
|
174
|
+
.join(', ');
|
|
175
|
+
info(`Detected stack: ${stackSummary || 'none'}`);
|
|
176
|
+
// Step 3: Match MCPs for detected stack
|
|
177
|
+
const allRecommendedMcps = matchMCPsForStack(detectedStack, {
|
|
178
|
+
includeInstalled: input.includeInstalled,
|
|
179
|
+
installedMcps
|
|
180
|
+
});
|
|
181
|
+
// Step 4: Check compatibility between installed MCPs
|
|
182
|
+
const installedReport = generateReport(installedMcps, getAllRules());
|
|
183
|
+
const installedCompatibility = convertToCompatibilityResult(installedReport);
|
|
184
|
+
// Step 5: Check recommendations against installed MCPs for conflicts
|
|
185
|
+
const excludedRecommendations = [];
|
|
186
|
+
const recommendationConflicts = [];
|
|
187
|
+
const safeRecommendations = [];
|
|
188
|
+
for (const rec of allRecommendedMcps) {
|
|
189
|
+
const canonicalRec = canonicalizeMcpId(rec.slug);
|
|
190
|
+
let hasConflict = false;
|
|
191
|
+
for (const installed of installedMcps) {
|
|
192
|
+
const rule = findRule(canonicalRec, installed);
|
|
193
|
+
if (rule && rule.status === 'conflict') {
|
|
194
|
+
hasConflict = true;
|
|
195
|
+
excludedRecommendations.push({
|
|
196
|
+
mcp: rec.slug,
|
|
197
|
+
reason: rule.reason,
|
|
198
|
+
conflictsWith: installed
|
|
199
|
+
});
|
|
200
|
+
recommendationConflicts.push({
|
|
201
|
+
recommended: rec.slug,
|
|
202
|
+
conflictsWith: installed,
|
|
203
|
+
reason: rule.reason
|
|
204
|
+
});
|
|
205
|
+
debug(`Excluded ${rec.slug}: conflicts with installed ${installed}`);
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (!hasConflict) {
|
|
210
|
+
safeRecommendations.push(rec);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
info(`Recommended ${safeRecommendations.length} MCPs (${excludedRecommendations.length} excluded due to conflicts)`);
|
|
214
|
+
// Step 6: Generate install configs for safe recommendations only
|
|
215
|
+
const installConfig = generateInstallConfig(safeRecommendations);
|
|
216
|
+
return {
|
|
217
|
+
detectedStack,
|
|
218
|
+
installedMcps,
|
|
219
|
+
recommendedMcps: safeRecommendations,
|
|
220
|
+
excludedRecommendations,
|
|
221
|
+
compatibility: {
|
|
222
|
+
installed: installedCompatibility,
|
|
223
|
+
recommendationConflicts
|
|
224
|
+
},
|
|
225
|
+
installConfig,
|
|
226
|
+
metadata: {
|
|
227
|
+
filesAnalyzed,
|
|
228
|
+
analysisDate: new Date().toISOString()
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
// ============================================================================
|
|
233
|
+
// TOOL HANDLER
|
|
234
|
+
// ============================================================================
|
|
235
|
+
/**
|
|
236
|
+
* Tool definition for MCP server registration.
|
|
237
|
+
*/
|
|
238
|
+
export const analyzeRepoMcpsTool = {
|
|
239
|
+
name: 'analyze_repo_mcps',
|
|
240
|
+
description: `Analyze your current repository to detect the tech stack and recommend relevant MCP servers.
|
|
241
|
+
|
|
242
|
+
This tool examines your project files (package.json, .env, config files, etc.) to:
|
|
243
|
+
1. Detect frontend, backend, database, auth, hosting, and payment technologies
|
|
244
|
+
2. Find already installed MCP servers
|
|
245
|
+
3. Recommend new MCPs that would enhance your development workflow
|
|
246
|
+
4. Generate ready-to-use install configurations for Cursor, Claude Desktop, and Windsurf
|
|
247
|
+
|
|
248
|
+
Example use cases:
|
|
249
|
+
- "What MCPs would help with my project?"
|
|
250
|
+
- "Analyze my repo and suggest useful MCP servers"
|
|
251
|
+
- "Which MCPs am I missing based on my tech stack?"`,
|
|
252
|
+
inputSchema: {
|
|
253
|
+
type: 'object',
|
|
254
|
+
properties: {
|
|
255
|
+
includeInstalled: {
|
|
256
|
+
type: 'boolean',
|
|
257
|
+
description: 'Include already installed MCPs in recommendations (default: false)',
|
|
258
|
+
default: false
|
|
259
|
+
},
|
|
260
|
+
mcpConfigPath: {
|
|
261
|
+
type: 'string',
|
|
262
|
+
description: 'Override path to MCP configuration file'
|
|
263
|
+
},
|
|
264
|
+
workspaceRoot: {
|
|
265
|
+
type: 'string',
|
|
266
|
+
description: 'Override workspace root directory (default: current directory)'
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
handler: async (params) => {
|
|
271
|
+
try {
|
|
272
|
+
const input = AnalyzeRepoMCPsInputSchema.parse(params);
|
|
273
|
+
const result = await analyzeRepo(input);
|
|
274
|
+
// Format output for display
|
|
275
|
+
const output = formatAnalysisOutput(result);
|
|
276
|
+
return {
|
|
277
|
+
content: [
|
|
278
|
+
{
|
|
279
|
+
type: 'text',
|
|
280
|
+
text: output
|
|
281
|
+
}
|
|
282
|
+
]
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
if (err instanceof z.ZodError) {
|
|
287
|
+
error('Invalid input:', err.errors);
|
|
288
|
+
return {
|
|
289
|
+
content: [
|
|
290
|
+
{
|
|
291
|
+
type: 'text',
|
|
292
|
+
text: `Invalid input: ${err.errors.map((e) => e.message).join(', ')}`
|
|
293
|
+
}
|
|
294
|
+
],
|
|
295
|
+
isError: true
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
error('analyze_repo_mcps error:', err);
|
|
299
|
+
throw err;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
// ============================================================================
|
|
304
|
+
// OUTPUT FORMATTING
|
|
305
|
+
// ============================================================================
|
|
306
|
+
/**
|
|
307
|
+
* Format analysis output for display.
|
|
308
|
+
*/
|
|
309
|
+
function formatAnalysisOutput(result) {
|
|
310
|
+
const lines = [];
|
|
311
|
+
lines.push('# Repository Analysis\n');
|
|
312
|
+
// Detected Stack
|
|
313
|
+
lines.push('## Detected Technologies\n');
|
|
314
|
+
const stackItems = [
|
|
315
|
+
result.detectedStack.frontend &&
|
|
316
|
+
`- **Frontend**: ${result.detectedStack.frontend.name}${result.detectedStack.frontend.version ? ` (${result.detectedStack.frontend.version})` : ''}`,
|
|
317
|
+
result.detectedStack.backend &&
|
|
318
|
+
`- **Backend**: ${result.detectedStack.backend.name}${result.detectedStack.backend.version ? ` (${result.detectedStack.backend.version})` : ''}`,
|
|
319
|
+
result.detectedStack.database &&
|
|
320
|
+
`- **Database**: ${result.detectedStack.database.name}${result.detectedStack.database.version ? ` (${result.detectedStack.database.version})` : ''}`,
|
|
321
|
+
result.detectedStack.orm &&
|
|
322
|
+
`- **ORM**: ${result.detectedStack.orm.name}${result.detectedStack.orm.version ? ` (${result.detectedStack.orm.version})` : ''}`,
|
|
323
|
+
result.detectedStack.auth &&
|
|
324
|
+
`- **Auth**: ${result.detectedStack.auth.name}${result.detectedStack.auth.version ? ` (${result.detectedStack.auth.version})` : ''}`,
|
|
325
|
+
result.detectedStack.hosting &&
|
|
326
|
+
`- **Hosting**: ${result.detectedStack.hosting.name}${result.detectedStack.hosting.version ? ` (${result.detectedStack.hosting.version})` : ''}`,
|
|
327
|
+
result.detectedStack.payments &&
|
|
328
|
+
`- **Payments**: ${result.detectedStack.payments.name}${result.detectedStack.payments.version ? ` (${result.detectedStack.payments.version})` : ''}`
|
|
329
|
+
].filter((item) => Boolean(item));
|
|
330
|
+
if (stackItems.length > 0) {
|
|
331
|
+
lines.push(...stackItems);
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
lines.push('_No technologies detected from project files._');
|
|
335
|
+
}
|
|
336
|
+
if (result.detectedStack.services.length > 0) {
|
|
337
|
+
lines.push('\n**Services**:');
|
|
338
|
+
for (const service of result.detectedStack.services) {
|
|
339
|
+
lines.push(`- ${service.name}`);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
lines.push('');
|
|
343
|
+
// Files Analyzed
|
|
344
|
+
lines.push('## Files Analyzed\n');
|
|
345
|
+
if (result.metadata.filesAnalyzed.length > 0) {
|
|
346
|
+
lines.push(result.metadata.filesAnalyzed.map((f) => `- \`${f}\``).join('\n'));
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
lines.push('_No recognized configuration files found._');
|
|
350
|
+
}
|
|
351
|
+
lines.push('');
|
|
352
|
+
// Installed MCPs + Compatibility
|
|
353
|
+
if (result.installedMcps.length > 0) {
|
|
354
|
+
lines.push('## Already Installed MCPs\n');
|
|
355
|
+
lines.push(result.installedMcps.map((m) => `- ${m}`).join('\n'));
|
|
356
|
+
lines.push('');
|
|
357
|
+
// Compatibility Report for installed MCPs
|
|
358
|
+
const compat = result.compatibility.installed;
|
|
359
|
+
const gradeEmoji = compat.grade === 'A' ? '🟢' : compat.grade === 'B' ? '🔵' : compat.grade === 'C' ? '🟡' : '🔴';
|
|
360
|
+
lines.push('### Compatibility Check\n');
|
|
361
|
+
lines.push(`**Health Score**: ${compat.score}/100 (Grade ${compat.grade}) ${gradeEmoji}\n`);
|
|
362
|
+
if (compat.conflicts.length > 0) {
|
|
363
|
+
lines.push('#### 🔴 Conflicts\n');
|
|
364
|
+
for (const conflict of compat.conflicts) {
|
|
365
|
+
const severity = conflict.severity === 'critical' ? '⚠️ Critical' : '⚡ Warning';
|
|
366
|
+
lines.push(`- **${conflict.mcpA}** ↔ **${conflict.mcpB}** (${severity})`);
|
|
367
|
+
lines.push(` - ${conflict.reason}`);
|
|
368
|
+
}
|
|
369
|
+
lines.push('');
|
|
370
|
+
}
|
|
371
|
+
if (compat.redundancies.length > 0) {
|
|
372
|
+
lines.push('#### 🟡 Redundancies\n');
|
|
373
|
+
for (const redundancy of compat.redundancies) {
|
|
374
|
+
lines.push(`- **${redundancy.mcpA}** ↔ **${redundancy.mcpB}**`);
|
|
375
|
+
lines.push(` - ${redundancy.reason}`);
|
|
376
|
+
}
|
|
377
|
+
lines.push('');
|
|
378
|
+
}
|
|
379
|
+
if (compat.synergies.length > 0) {
|
|
380
|
+
lines.push('#### 🔵 Synergies\n');
|
|
381
|
+
for (const synergy of compat.synergies) {
|
|
382
|
+
lines.push(`- **${synergy.mcpA}** + **${synergy.mcpB}** ✨`);
|
|
383
|
+
lines.push(` - ${synergy.reason}`);
|
|
384
|
+
}
|
|
385
|
+
lines.push('');
|
|
386
|
+
}
|
|
387
|
+
if (compat.suggestions.length > 0) {
|
|
388
|
+
lines.push('#### 💡 Suggestions\n');
|
|
389
|
+
for (const suggestion of compat.suggestions) {
|
|
390
|
+
lines.push(`- Consider adding **${suggestion.mcp}**`);
|
|
391
|
+
lines.push(` - ${suggestion.reason} (pairs well with ${suggestion.basedOn})`);
|
|
392
|
+
}
|
|
393
|
+
lines.push('');
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
// Excluded Recommendations (due to conflicts)
|
|
397
|
+
if (result.excludedRecommendations.length > 0) {
|
|
398
|
+
lines.push('## Excluded Recommendations\n');
|
|
399
|
+
lines.push('_The following MCPs were not recommended due to conflicts with your installed MCPs:_\n');
|
|
400
|
+
for (const excluded of result.excludedRecommendations) {
|
|
401
|
+
lines.push(`- **${excluded.mcp}** conflicts with \`${excluded.conflictsWith}\``);
|
|
402
|
+
lines.push(` - ${excluded.reason}`);
|
|
403
|
+
}
|
|
404
|
+
lines.push('');
|
|
405
|
+
}
|
|
406
|
+
// Recommended MCPs
|
|
407
|
+
lines.push('## Recommended MCPs\n');
|
|
408
|
+
if (result.recommendedMcps.length === 0) {
|
|
409
|
+
lines.push('_No additional MCPs recommended. You have everything you need!_');
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
// Group by priority
|
|
413
|
+
const highPriority = result.recommendedMcps.filter((m) => m.priority === 'high');
|
|
414
|
+
const mediumPriority = result.recommendedMcps.filter((m) => m.priority === 'medium');
|
|
415
|
+
const lowPriority = result.recommendedMcps.filter((m) => m.priority === 'low');
|
|
416
|
+
if (highPriority.length > 0) {
|
|
417
|
+
lines.push('### 🔴 High Priority\n');
|
|
418
|
+
for (const mcp of highPriority) {
|
|
419
|
+
lines.push(`**${mcp.name}** (\`${mcp.slug}\`)`);
|
|
420
|
+
lines.push(`- ${mcp.description}`);
|
|
421
|
+
lines.push(`- _Matched: ${mcp.matchedTech}_`);
|
|
422
|
+
lines.push('');
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (mediumPriority.length > 0) {
|
|
426
|
+
lines.push('### 🟡 Medium Priority\n');
|
|
427
|
+
for (const mcp of mediumPriority) {
|
|
428
|
+
lines.push(`**${mcp.name}** (\`${mcp.slug}\`)`);
|
|
429
|
+
lines.push(`- ${mcp.description}`);
|
|
430
|
+
lines.push(`- _Matched: ${mcp.matchedTech}_`);
|
|
431
|
+
lines.push('');
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
if (lowPriority.length > 0) {
|
|
435
|
+
lines.push('### 🟢 Low Priority\n');
|
|
436
|
+
for (const mcp of lowPriority) {
|
|
437
|
+
lines.push(`**${mcp.name}** (\`${mcp.slug}\`)`);
|
|
438
|
+
lines.push(`- ${mcp.description}`);
|
|
439
|
+
lines.push(`- _Matched: ${mcp.matchedTech}_`);
|
|
440
|
+
lines.push('');
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
// Quick Install
|
|
445
|
+
if (result.recommendedMcps.length > 0) {
|
|
446
|
+
lines.push('## Quick Install\n');
|
|
447
|
+
lines.push('Add to your Claude Desktop config (`claude_desktop_config.json`):\n');
|
|
448
|
+
lines.push('```json');
|
|
449
|
+
lines.push(JSON.stringify(result.installConfig.claudeDesktop, null, 2));
|
|
450
|
+
lines.push('```\n');
|
|
451
|
+
}
|
|
452
|
+
// Metadata
|
|
453
|
+
lines.push(`---\n_Analysis completed: ${result.metadata.analysisDate}_`);
|
|
454
|
+
return lines.join('\n');
|
|
455
|
+
}
|
|
456
|
+
//# sourceMappingURL=analyze-repo.js.map
|