@xiaohui-wang/mcpadvisor
Version:
MCP Advisor & Installation - Find the right MCP server for your needs
132 lines (131 loc) • 5.99 kB
JavaScript
import { GitHubReadmeExtractor } from './extractors/GitHubReadmeExtractor.js';
import { ExtractorFactory } from './factories/ExtractorFactory.js';
import { FormatterFactory } from './factories/FormatterFactory.js';
import logger from '../../../utils/logger.js';
/**
* Installation Guide Service
* Follows SOLID principles with dependency injection and separation of concerns
*
* Single Responsibility: Orchestrates the installation guide generation process
* Open/Closed: Extensible through new extractors and formatters without modification
* Liskov Substitution: All extractors and formatters are interchangeable
* Interface Segregation: Focused interfaces for specific responsibilities
* Dependency Inversion: Depends on abstractions, not concrete implementations
*/
export class InstallationGuideService {
readmeExtractor;
/**
* Constructor with dependency injection
* @param readmeExtractor - README content extractor (defaults to GitHub extractor)
*/
constructor(readmeExtractor) {
this.readmeExtractor = readmeExtractor || new GitHubReadmeExtractor();
}
/**
* Generate MCP installation guide
* Main orchestration method that coordinates different components
*
* @param githubUrl - GitHub repository URL
* @param mcpName - MCP name
* @returns Installation guide content
*/
async generateInstallationGuide(githubUrl, mcpName) {
try {
// Step 1: Extract README content
const readmeContent = await this.readmeExtractor.extractReadmeContent(githubUrl);
if (!readmeContent) {
return this.generateDefaultGuide(mcpName, githubUrl);
}
// Step 2: Create installation guide context
const context = await this.createInstallationGuideContext(readmeContent, mcpName, githubUrl);
// Step 3: Select appropriate formatter and generate guide
const formatter = FormatterFactory.getBestFormatter(context);
const result = formatter.formatGuide(context);
if (!result.success) {
logger.error(`Failed to format guide: ${result.error}`);
return this.generateDefaultGuide(mcpName, githubUrl);
}
return result.content;
}
catch (error) {
logger.error(`Failed to generate installation guide: ${error instanceof Error ? error.message : String(error)}`);
return this.generateDefaultGuide(mcpName, githubUrl);
}
}
/**
* Create installation guide context by extracting relevant information
* @param readmeContent - README content
* @param mcpName - MCP name
* @param githubUrl - GitHub repository URL
* @returns Installation guide context
*/
async createInstallationGuideContext(readmeContent, mcpName, githubUrl) {
// Extract repository name from URL
const repoName = this.extractRepoName(githubUrl);
// Select best extractor for the content
const extractor = ExtractorFactory.getBestExtractor(readmeContent);
// Extract installation section
const installationSection = extractor.extractInstallationSection(readmeContent);
return {
mcpName,
githubUrl,
repoName,
installationSection,
};
}
/**
* Generate default installation guide when README is not available
* @param mcpName - MCP name
* @param githubUrl - GitHub repository URL
* @returns Default installation guide
*/
generateDefaultGuide(mcpName, githubUrl) {
const repoName = this.extractRepoName(githubUrl);
let guide = `我将指导你如何安装和配置 ${mcpName} MCP 服务器。\n\n`;
guide += `GitHub 仓库地址:${githubUrl}\n\n`;
guide += `## 安装步骤\n\n`;
guide += `由于无法获取项目的 README 文档,请按照以下通用步骤进行安装:\n\n`;
guide += `1. **克隆仓库**:\n`;
guide += ` \`\`\`bash\n git clone ${githubUrl}\n \`\`\`\n\n`;
guide += `2. **进入项目目录**:\n`;
guide += ` \`\`\`bash\n cd ${repoName}\n \`\`\`\n\n`;
guide += `3. **安装依赖**:\n`;
guide += ` \`\`\`bash\n npm install\n \`\`\`\n\n`;
guide += `4. **查看项目文档**:\n`;
guide += ` 请查看项目中的 README.md、package.json 或其他文档文件了解具体的安装和配置步骤。\n\n`;
guide += `## MCP 配置\n\n`;
guide += `如果这是一个 MCP 服务器,你可能需要:\n\n`;
guide += `1. 查看项目文档了解如何配置 MCP 客户端\n`;
guide += `2. 将服务器配置添加到 Claude Desktop 或其他 MCP 客户端的配置文件中\n`;
guide += `3. 重启 MCP 客户端以加载新配置\n\n`;
guide += `## 需要帮助?\n\n`;
guide += `- 查看项目的 [GitHub 页面](${githubUrl}) 获取最新文档\n`;
guide += `- 查看项目的 [Issues 页面](${githubUrl}/issues) 寻找解决方案\n`;
guide += `- 创建新的 Issue 寻求帮助\n`;
return guide;
}
/**
* Extract repository name from GitHub URL
* @param githubUrl - GitHub repository URL
* @returns Repository name
*/
/**
* Extract repository name from GitHub URL
* (kept public for backward-compatibility with existing tests)
*/
extractRepoName(githubUrl) {
try {
const url = new URL(githubUrl);
const pathParts = url.pathname.split('/').filter(part => part.length > 0);
let repo = pathParts[1] || 'unknown-repo';
// Remove .git suffix if present for compatibility with legacy tests
if (repo.endsWith('.git')) {
repo = repo.replace(/\.git$/i, '');
}
return repo;
}
catch {
return 'unknown-repo';
}
}
}