UNPKG

mcp-ai-agent-guidelines

Version:

A comprehensive Model Context Protocol server providing advanced tools, resources, and prompts for implementing AI agent best practices

778 lines (772 loc) 31.4 kB
import { z } from "zod"; import { detectParser, getParserForFileType, } from "./dependency-auditor/index.js"; import { buildFurtherReadingSection, buildOptionalSectionsMap, } from "./shared/prompt-utils.js"; /** * Supported file types for multi-language dependency auditing */ const FileTypeEnum = z.enum([ "package.json", "requirements.txt", "pyproject.toml", "pipfile", "go.mod", "Cargo.toml", "Gemfile", "vcpkg.json", "conanfile.txt", "rockspec", "csproj", "uv.lock", "yarn.lock", "tsconfig.json", "auto", ]); const DependencyAuditorSchema = z.object({ // Primary content input - supports any language dependencyContent: z .string() .optional() .describe("Content of dependency file (package.json, requirements.txt, go.mod, Cargo.toml, Gemfile, csproj, etc.)"), // Backward compatibility: packageJsonContent still works for JS/TS packageJsonContent: z .string() .optional() .describe("Content of package.json file (deprecated: use dependencyContent)"), // File type specification fileType: FileTypeEnum.optional() .default("auto") .describe("Type of dependency file. Use 'auto' for automatic detection based on content."), // Analysis options checkOutdated: z.boolean().optional().default(true), checkDeprecated: z.boolean().optional().default(true), checkVulnerabilities: z.boolean().optional().default(true), suggestAlternatives: z.boolean().optional().default(true), analyzeBundleSize: z.boolean().optional().default(true), // Output options includeReferences: z.boolean().optional().default(true), includeMetadata: z.boolean().optional().default(true), inputFile: z.string().optional(), }); export async function dependencyAuditor(args) { const input = DependencyAuditorSchema.parse(args); // Get content from either new or legacy parameter const content = input.dependencyContent || input.packageJsonContent; if (!content) { return { content: [ { type: "text", text: `## ❌ Error\n\nNo dependency content provided. Please provide either 'dependencyContent' or 'packageJsonContent'.`, }, ], }; } // Determine file type and get appropriate parser const fileType = input.fileType; let parser = null; if (fileType && fileType !== "auto") { parser = getParserForFileType(fileType); } if (!parser) { parser = detectParser(content); } if (!parser) { // Fall back to legacy package.json handling for backward compatibility return handleLegacyPackageJson(content, input); } // Parse and analyze using the new multi-language system const parseResult = parser.parse(content); if (parseResult.errors && parseResult.errors.length > 0) { return { content: [ { type: "text", text: `## ❌ Error\n\n${parseResult.errors.join("\n")}`, }, ], }; } const analysisResult = parser.analyze(parseResult, { checkOutdated: input.checkOutdated, checkDeprecated: input.checkDeprecated, checkVulnerabilities: input.checkVulnerabilities, suggestAlternatives: input.suggestAlternatives, analyzeBundleSize: input.analyzeBundleSize, }); // Build optional sections using the shared utility const { references, metadata } = buildOptionalSectionsMap(input, { references: { key: "includeReferences", builder: () => buildFurtherReadingSection(getEcosystemReferences(analysisResult.ecosystem)), }, metadata: { key: "includeMetadata", builder: (cfg) => [ "### Metadata", `- Updated: ${new Date().toISOString().slice(0, 10)}`, "- Source tool: mcp_ai-agent-guid_dependency-auditor", `- Ecosystem: ${analysisResult.ecosystem}`, `- File type: ${analysisResult.fileType}`, cfg.inputFile ? `- Input file: ${cfg.inputFile}` : undefined, "", ] .filter(Boolean) .join("\n"), }, }); return { content: [ { type: "text", text: generateMultiLanguageReport(analysisResult, metadata, references), }, ], }; } /** * Handle legacy package.json for backward compatibility */ export function handleLegacyPackageJson(content, input) { let packageJson; try { packageJson = JSON.parse(content); } catch (error) { return { content: [ { type: "text", text: `## ❌ Error\n\nInvalid content: ${error instanceof Error ? error.message : "Unknown error"}\n\nSupported formats: package.json, requirements.txt, pyproject.toml, go.mod, Cargo.toml, Gemfile, vcpkg.json, rockspec`, }, ], }; } const analysis = analyzeLegacyDependencies(packageJson, input); // Build optional sections using the shared utility const { references, metadata } = buildOptionalSectionsMap(input, { references: { key: "includeReferences", builder: () => buildFurtherReadingSection([ { title: "NPM Audit Official Guide", url: "https://docs.npmjs.com/auditing-package-dependencies-for-security-vulnerabilities", description: "Official documentation for auditing package dependencies", }, { title: "Understanding NPM Audit", url: "https://www.niraj.life/blog/understanding-npm-audit-fixing-vulnerabilities-nodejs/", description: "Practical guide to fixing vulnerabilities in Node.js projects", }, { title: "Dependency Tree Analysis", url: "https://www.jit.io/resources/appsec-tools/guide-to-using-npm-audit-to-create-a-dependency-tree", description: "Using npm audit to visualize and analyze dependency trees", }, { title: "Advanced Dependency Management", url: "https://www.jit.io/resources/appsec-tools/guide-to-using-npm-audit-to-create-a-dependency-tree", description: "Developer tutorial for comprehensive dependency scanning", }, ]), }, metadata: { key: "includeMetadata", builder: (cfg) => [ "### Metadata", `- Updated: ${new Date().toISOString().slice(0, 10)}`, "- Source tool: mcp_ai-agent-guid_dependency-auditor", cfg.inputFile ? `- Input file: ${cfg.inputFile}` : undefined, "", ] .filter(Boolean) .join("\n"), }, }); return { content: [ { type: "text", text: generateLegacyReport(packageJson, analysis, metadata, references), }, ], }; } function analyzeLegacyDependencies(packageJson, input) { const issues = []; const recommendations = []; const packages = []; // Collect all packages if (packageJson.dependencies) { for (const [name, version] of Object.entries(packageJson.dependencies)) { packages.push({ name, version, type: "dependencies" }); } } if (packageJson.devDependencies) { for (const [name, version] of Object.entries(packageJson.devDependencies)) { packages.push({ name, version, type: "devDependencies" }); } } if (packageJson.peerDependencies) { for (const [name, version] of Object.entries(packageJson.peerDependencies)) { packages.push({ name, version, type: "peerDependencies" }); } } // Check for outdated version patterns if (input.checkOutdated) { for (const pkg of packages) { // Check for wildcard versions (security risk) if (pkg.version === "*" || pkg.version === "latest") { issues.push({ package: pkg.name, version: pkg.version, type: "Unpinned Version", severity: "moderate", description: `Using wildcard version (${pkg.version}) which can lead to unexpected updates`, recommendation: "Pin to a specific version or use caret (^) or tilde (~) ranges", }); } // Check for very old version patterns (pre-1.0) if (pkg.version.match(/^[~^]?0\.[0-9]+\.[0-9]+/)) { issues.push({ package: pkg.name, version: pkg.version, type: "Pre-1.0 Version", severity: "info", description: "Package is pre-1.0, which may indicate instability or breaking changes", recommendation: "Check if a stable 1.x+ version is available", }); } // Check for very specific pinned versions without range if (pkg.version.match(/^[0-9]+\.[0-9]+\.[0-9]+$/)) { issues.push({ package: pkg.name, version: pkg.version, type: "Exact Version Pin", severity: "low", description: "Exact version pinning prevents automatic security updates", recommendation: "Consider using caret (^) ranges to allow patch updates", }); } } } // Check for deprecated packages (common ones) if (input.checkDeprecated) { const deprecatedPackages = { request: { reason: "Deprecated since 2020", alternative: "Use axios, node-fetch, or native fetch", }, "node-uuid": { reason: "Renamed to uuid", alternative: "Use uuid package", }, colors: { reason: "Security concerns and maintenance issues", alternative: "Use chalk or picocolors", }, faker: { reason: "Original package deprecated", alternative: "Use @faker-js/faker", }, tslint: { reason: "Deprecated in favor of ESLint", alternative: "Use @typescript-eslint/eslint-plugin", }, }; for (const pkg of packages) { if (deprecatedPackages[pkg.name]) { const { reason, alternative } = deprecatedPackages[pkg.name]; issues.push({ package: pkg.name, version: pkg.version, type: "Deprecated Package", severity: "high", description: reason, recommendation: alternative, }); } } } // Check for known vulnerable patterns if (input.checkVulnerabilities) { // Check for vulnerable lodash versions (below 4.17.21) const lodashPkg = packages.find((p) => p.name === "lodash"); if (lodashPkg && (lodashPkg.version.match(/^[~^]?[0-3]\./) || lodashPkg.version.match(/^[~^]?4\.(0|1[0-6]|17\.(0|1[0-9]|20))($|[^\d])/))) { issues.push({ package: "lodash", version: lodashPkg.version, type: "Known Vulnerabilities", severity: "moderate", description: "Lodash versions below 4.17.21 have known security vulnerabilities", recommendation: "Update to lodash@^4.17.21 or use lodash-es", }); } // Check for old moment.js (deprecated and has issues) const momentPkg = packages.find((p) => p.name === "moment"); if (momentPkg) { issues.push({ package: "moment", version: momentPkg.version, type: "Deprecated & Bundle Size", severity: "moderate", description: "Moment.js is in maintenance mode and has large bundle size", recommendation: "Consider migrating to date-fns, dayjs, or Temporal API", }); } // Check for vulnerable axios versions (below 1.6.0) const axiosPkg = packages.find((p) => p.name === "axios"); if (axiosPkg && (axiosPkg.version.match(/^[~^]?0\./) || axiosPkg.version.match(/^[~^]?1\.[0-5]($|\.)/))) { issues.push({ package: "axios", version: axiosPkg.version, type: "Known Vulnerabilities", severity: "high", description: "Axios versions below 1.6.0 have known security vulnerabilities", recommendation: "Update to axios@^1.6.0 or later", }); } } // Suggest ESM alternatives if (input.suggestAlternatives) { const esmAlternatives = { "node-fetch": "Use native fetch (Node.js 18+) or undici", "cross-fetch": "Use native fetch (Node.js 18+)", "isomorphic-fetch": "Use native fetch (Node.js 18+)", "es6-promise": "Use native Promises", "babel-polyfill": "Use targeted polyfills or core-js", "@babel/polyfill": "Use targeted polyfills or core-js", }; for (const pkg of packages) { if (esmAlternatives[pkg.name]) { issues.push({ package: pkg.name, version: pkg.version, type: "ESM Alternative Available", severity: "info", description: "Modern ESM-compatible alternative available", recommendation: esmAlternatives[pkg.name], }); } } } // Check for bundle size concerns if (input.analyzeBundleSize) { const largeBundlePackages = { moment: "~300KB - Consider date-fns (~25KB) or dayjs (~2KB)", lodash: "~70KB - Consider lodash-es with tree-shaking", "core-js": "~100KB - Use only needed polyfills", jquery: "~90KB - Consider vanilla JS or smaller alternatives", }; for (const pkg of packages) { if (largeBundlePackages[pkg.name] && pkg.type === "dependencies") { issues.push({ package: pkg.name, version: pkg.version, type: "Bundle Size Concern", severity: "low", description: `Large bundle size: ${largeBundlePackages[pkg.name]}`, recommendation: "Consider tree-shaking or smaller alternatives", }); } } } // Generate general recommendations if (issues.length > 0) { const criticalCount = issues.filter((i) => i.severity === "critical").length; const highCount = issues.filter((i) => i.severity === "high").length; const moderateCount = issues.filter((i) => i.severity === "moderate").length; if (criticalCount > 0) { recommendations.push(`Address ${criticalCount} critical issue(s) immediately`); } if (highCount > 0) { recommendations.push(`Update ${highCount} high-priority package(s) as soon as possible`); } if (moderateCount > 0) { recommendations.push(`Review ${moderateCount} moderate concern(s)`); } recommendations.push("Run 'npm audit' for detailed vulnerability analysis"); recommendations.push("Run 'npm outdated' to check for latest versions"); recommendations.push("Consider using 'npm audit fix' for automated security updates"); recommendations.push("Review package.json regularly for updates"); recommendations.push("Use Dependabot or Renovate for automated dependency updates"); } else { recommendations.push("No immediate issues detected in dependency versions"); recommendations.push("Continue monitoring dependencies with 'npm audit'"); recommendations.push("Keep dependencies up-to-date with regular reviews"); } return { packages, issues, recommendations, }; } /** * Get ecosystem-specific reference links */ function getEcosystemReferences(ecosystem) { const refs = { javascript: [ { title: "NPM Audit Official Guide", url: "https://docs.npmjs.com/auditing-package-dependencies-for-security-vulnerabilities", description: "Official documentation for auditing package dependencies", }, { title: "NPM Security Best Practices", url: "https://docs.npmjs.com/packages-and-modules/securing-your-code", description: "Best practices for securing Node.js projects", }, ], python: [ { title: "pip-audit", url: "https://pypi.org/project/pip-audit/", description: "Scan Python environments for packages with known vulnerabilities", }, { title: "Safety CLI", url: "https://safetycli.com/", description: "Python dependency vulnerability scanner", }, { title: "Python Packaging Security", url: "https://packaging.python.org/en/latest/guides/analyzing-pypi-package-downloads/", description: "Python packaging security best practices", }, ], go: [ { title: "govulncheck", url: "https://go.dev/blog/vuln", description: "Official Go vulnerability database and scanner", }, { title: "Go Module Security", url: "https://go.dev/doc/modules/managing-dependencies", description: "Managing dependencies securely in Go", }, ], rust: [ { title: "cargo-audit", url: "https://rustsec.org/", description: "Audit Cargo.lock for security vulnerabilities", }, { title: "RustSec Advisory Database", url: "https://github.com/RustSec/advisory-db", description: "Security advisory database for Rust crates", }, ], ruby: [ { title: "bundler-audit", url: "https://github.com/rubysec/bundler-audit", description: "Patch-level verification for Ruby dependencies", }, { title: "Ruby Advisory Database", url: "https://rubysec.com/", description: "Security advisories for Ruby gems", }, ], cpp: [ { title: "vcpkg Security", url: "https://vcpkg.io/en/docs/users/versioning.html", description: "vcpkg versioning and security documentation", }, { title: "C++ Package Management", url: "https://isocpp.org/wiki/faq/cpp-package-management", description: "C++ dependency management best practices", }, ], lua: [ { title: "LuaRocks Documentation", url: "https://luarocks.org/", description: "LuaRocks package manager documentation", }, ], dotnet: [ { title: "NuGet Security", url: "https://docs.microsoft.com/en-us/nuget/concepts/security-best-practices", description: "NuGet security best practices", }, { title: ".NET Security Advisories", url: "https://github.com/dotnet/announcements/issues?q=is%3Aissue+label%3ASecurity", description: "Official .NET security announcements", }, { title: "dotnet list package --vulnerable", url: "https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-list-package", description: "Built-in vulnerability scanning for .NET", }, ], typescript: [ { title: "TypeScript Configuration", url: "https://www.typescriptlang.org/tsconfig", description: "Official TypeScript configuration documentation", }, { title: "DefinitelyTyped", url: "https://github.com/DefinitelyTyped/DefinitelyTyped", description: "TypeScript type definitions repository", }, { title: "TypeScript Strict Mode", url: "https://www.typescriptlang.org/docs/handbook/2/basic-types.html#strictness", description: "TypeScript strict mode documentation", }, ], }; return refs[ecosystem] || []; } /** * Generate report for multi-language analysis results */ function generateMultiLanguageReport(analysis, metadata, references) { const { packages, issues, recommendations, ecosystem, projectName, projectVersion, } = analysis; // Group issues by severity const criticalIssues = issues.filter((i) => i.severity === "critical"); const highIssues = issues.filter((i) => i.severity === "high"); const moderateIssues = issues.filter((i) => i.severity === "moderate"); const lowIssues = issues.filter((i) => i.severity === "low"); const infoIssues = issues.filter((i) => i.severity === "info"); // Get dependency counts by type const depCounts = { dependencies: packages.filter((p) => p.type === "dependencies").length, devDependencies: packages.filter((p) => p.type === "devDependencies") .length, optionalDependencies: packages.filter((p) => p.type === "optionalDependencies").length, buildDependencies: packages.filter((p) => p.type === "buildDependencies") .length, peerDependencies: packages.filter((p) => p.type === "peerDependencies") .length, }; const ecosystemEmoji = getEcosystemEmoji(ecosystem); let report = `## ${ecosystemEmoji} Dependency Audit Report ${metadata} ### 📋 Summary | Metric | Value | |---|---| | Project | ${projectName || "Unknown"} | | Version | ${projectVersion || "Unknown"} | | Ecosystem | ${ecosystem} | | Total Packages | ${packages.length} | | Dependencies | ${depCounts.dependencies} | | Dev Dependencies | ${depCounts.devDependencies} | | Peer Dependencies | ${depCounts.peerDependencies} | | Optional/Build | ${depCounts.optionalDependencies + depCounts.buildDependencies} | | Issues Found | ${issues.length} | | Critical | ${criticalIssues.length} | | High | ${highIssues.length} | | Moderate | ${moderateIssues.length} | | Low | ${lowIssues.length} | `; if (issues.length > 0) { report += `### 🚨 Issues by Severity\n\n`; if (criticalIssues.length > 0) { report += `#### 🔴 Critical (${criticalIssues.length})\n`; for (const issue of criticalIssues) { report += formatMultiLangIssue(issue); } report += "\n"; } if (highIssues.length > 0) { report += `#### 🟠 High (${highIssues.length})\n`; for (const issue of highIssues) { report += formatMultiLangIssue(issue); } report += "\n"; } if (moderateIssues.length > 0) { report += `#### 🟡 Moderate (${moderateIssues.length})\n`; for (const issue of moderateIssues) { report += formatMultiLangIssue(issue); } report += "\n"; } if (lowIssues.length > 0) { report += `#### 🔵 Low (${lowIssues.length})\n`; for (const issue of lowIssues) { report += formatMultiLangIssue(issue); } report += "\n"; } if (infoIssues.length > 0) { report += `#### ℹ️ Info (${infoIssues.length})\n`; for (const issue of infoIssues) { report += formatMultiLangIssue(issue); } report += "\n"; } // Add issues table report += `### 📊 Issues Table\n`; report += `| Package | Version | Type | Severity | Description |\n`; report += `|---|---|---|---|---|\n`; for (const issue of issues) { report += `| ${issue.package} | ${issue.version} | ${issue.type} | ${getSeverityEmoji(issue.severity)} ${issue.severity} | ${issue.description} |\n`; } report += "\n"; } else { report += `### ✅ No Issues Detected\n\nAll dependencies appear to be up-to-date and secure based on static analysis.\n\n`; } report += `### 💡 Recommendations\n`; for (let i = 0; i < recommendations.length; i++) { report += `${i + 1}. ${recommendations[i]}\n`; } if (references) { report += `\n${references}\n`; } report += `\n### ⚠️ Disclaimer\n`; report += `- This is a static analysis based on known patterns and common issues.\n`; report += `- Use ecosystem-specific tools for real-time vulnerability scanning.\n`; report += `- Always test dependency updates in a development environment before deploying to production.\n`; report += `- This tool provides recommendations, but final decisions should be based on your specific project requirements.\n`; return report; } function formatMultiLangIssue(issue) { let formatted = `**${issue.package}@${issue.version}** - ${issue.type}\n`; formatted += ` - ${issue.description}\n`; if (issue.recommendation) { formatted += ` - 💡 **Recommendation**: ${issue.recommendation}\n`; } return `${formatted}\n`; } function getEcosystemEmoji(ecosystem) { const emojis = { javascript: "📦", typescript: "📘", python: "🐍", go: "🐹", rust: "🦀", ruby: "💎", cpp: "⚡", lua: "🌙", dotnet: "🔷", }; return emojis[ecosystem] || "📦"; } function generateLegacyReport(packageJson, analysis, metadata, references) { const { packages, issues, recommendations } = analysis; // Group issues by severity const criticalIssues = issues.filter((i) => i.severity === "critical"); const highIssues = issues.filter((i) => i.severity === "high"); const moderateIssues = issues.filter((i) => i.severity === "moderate"); const lowIssues = issues.filter((i) => i.severity === "low"); const infoIssues = issues.filter((i) => i.severity === "info"); let report = `## 📦 Dependency Audit Report ${metadata} ### 📋 Summary | Metric | Value | |---|---| | Project | ${packageJson.name || "Unknown"} | | Version | ${packageJson.version || "Unknown"} | | Total Dependencies | ${packages.filter((p) => p.type === "dependencies").length} | | Dev Dependencies | ${packages.filter((p) => p.type === "devDependencies").length} | | Peer Dependencies | ${packages.filter((p) => p.type === "peerDependencies").length} | | Issues Found | ${issues.length} | | Critical | ${criticalIssues.length} | | High | ${highIssues.length} | | Moderate | ${moderateIssues.length} | | Low | ${lowIssues.length} | `; if (issues.length > 0) { report += `### 🚨 Issues by Severity\n\n`; if (criticalIssues.length > 0) { report += `#### 🔴 Critical (${criticalIssues.length})\n`; for (const issue of criticalIssues) { report += formatIssue(issue); } report += "\n"; } if (highIssues.length > 0) { report += `#### 🟠 High (${highIssues.length})\n`; for (const issue of highIssues) { report += formatIssue(issue); } report += "\n"; } if (moderateIssues.length > 0) { report += `#### 🟡 Moderate (${moderateIssues.length})\n`; for (const issue of moderateIssues) { report += formatIssue(issue); } report += "\n"; } if (lowIssues.length > 0) { report += `#### 🔵 Low (${lowIssues.length})\n`; for (const issue of lowIssues) { report += formatIssue(issue); } report += "\n"; } if (infoIssues.length > 0) { report += `#### ℹ️ Info (${infoIssues.length})\n`; for (const issue of infoIssues) { report += formatIssue(issue); } report += "\n"; } // Add issues table report += `### 📊 Issues Table\n`; report += `| Package | Version | Type | Severity | Description |\n`; report += `|---|---|---|---|---|\n`; for (const issue of issues) { report += `| ${issue.package} | ${issue.version} | ${issue.type} | ${getSeverityEmoji(issue.severity)} ${issue.severity} | ${issue.description} |\n`; } report += "\n"; } else { report += `### ✅ No Issues Detected\n\nAll dependencies appear to be up-to-date and secure based on static analysis.\n\n`; } report += `### 💡 Recommendations\n`; for (let i = 0; i < recommendations.length; i++) { report += `${i + 1}. ${recommendations[i]}\n`; } if (references) { report += `\n${references}\n`; } report += `\n### ⚠️ Disclaimer\n`; report += `- This is a static analysis based on known patterns and common issues.\n`; report += `- Run \`npm audit\` for real-time vulnerability scanning against the npm advisory database.\n`; report += `- Always test dependency updates in a development environment before deploying to production.\n`; report += `- This tool provides recommendations, but final decisions should be based on your specific project requirements.\n`; return report; } function formatIssue(issue) { let formatted = `**${issue.package}@${issue.version}** - ${issue.type}\n`; formatted += ` - ${issue.description}\n`; if (issue.recommendation) { formatted += ` - 💡 **Recommendation**: ${issue.recommendation}\n`; } return `${formatted}\n`; } function getSeverityEmoji(severity) { switch (severity) { case "critical": return "🔴"; case "high": return "🟠"; case "moderate": return "🟡"; case "low": return "🔵"; case "info": return "ℹ️"; default: return "⚪"; } } //# sourceMappingURL=dependency-auditor.js.map