Skip to main content
Glama
MausRundung362

Project Explorer MCP Server

check_outdated

Identify outdated npm packages in your project's dependencies by analyzing package.json to show available newer versions.

Instructions

Check for outdated npm packages in package.json using 'npm outdated'. Analyzes the current project's dependencies and shows which packages have newer versions available. Requires npm to be installed and accessible from the command line.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectPathNoPath to the directory containing package.json. Defaults to the first allowed directory if not specified.
includeDevDependenciesNoWhether to include dev dependencies in the check
outputFormatNoFormat of the output: detailed (full info), summary (counts only), or raw (npm command output)detailed

Implementation Reference

  • The main handler function that implements the 'check_outdated' tool. It validates input, checks permissions, runs 'npm outdated --json', parses the output, categorizes packages, and returns formatted results (detailed, summary, or raw).
    export async function handleCheckOutdated(args: any, allowedDirectories: string[]) { const { projectPath = allowedDirectories[0], includeDevDependencies = true, outputFormat = "detailed" } = args; if (!projectPath) { throw new McpError(ErrorCode.InvalidParams, "No project path specified and no allowed directories available"); } // Resolve to absolute path const resolvedPath = path.resolve(projectPath); // Check if path is within allowed directories const isPathAllowed = allowedDirectories.some(dir => { const normalizedDir = path.resolve(dir).replace(/\\/g, '/'); const normalizedPath = resolvedPath.replace(/\\/g, '/'); return normalizedPath === normalizedDir || normalizedPath.startsWith(normalizedDir + '/'); }); if (!isPathAllowed) { throw new McpError(ErrorCode.InvalidParams, `Path "${resolvedPath}" is not within allowed directories`); } // Check if package.json exists const packageJsonPath = path.join(resolvedPath, 'package.json'); if (!fs.existsSync(packageJsonPath)) { throw new McpError(ErrorCode.InvalidParams, `package.json not found in "${resolvedPath}"`); } try { // Build npm outdated command let command = 'npm outdated --json'; if (!includeDevDependencies) { command += ' --prod'; } // Execute npm outdated command const { stdout, stderr } = await execAsync(command, { cwd: resolvedPath, timeout: 10000 // 10 second timeout }); let outdatedData: any = {}; let rawOutput = stdout || stderr; // npm outdated returns exit code 1 when packages are outdated, so we need to handle both stdout and stderr if (stdout && stdout.trim()) { try { outdatedData = JSON.parse(stdout); } catch (parseError) { // If JSON parsing fails, treat as no outdated packages outdatedData = {}; } } else if (stderr && stderr.includes('{')) { try { // Sometimes npm outputs to stderr outdatedData = JSON.parse(stderr); } catch (parseError) { outdatedData = {}; } } // Parse the outdated packages const outdatedPackages: OutdatedPackage[] = []; for (const [packageName, info] of Object.entries(outdatedData)) { if (typeof info === 'object' && info !== null) { const packageInfo = info as any; outdatedPackages.push({ package: packageName, current: packageInfo.current || 'unknown', wanted: packageInfo.wanted || 'unknown', latest: packageInfo.latest || 'unknown', location: packageInfo.location || resolvedPath, type: packageInfo.type || 'dependencies' }); } } const totalOutdated = outdatedPackages.length; const hasOutdated = totalOutdated > 0; let message: string; if (!hasOutdated) { message = "All packages are up to date! 🎉"; } else { message = `Found ${totalOutdated} outdated package${totalOutdated === 1 ? '' : 's'}`; if (outputFormat === "detailed") { message += ":\n\n"; outdatedPackages.forEach(pkg => { message += `📦 ${pkg.package}\n`; message += ` Current: ${pkg.current}\n`; message += ` Wanted: ${pkg.wanted}\n`; message += ` Latest: ${pkg.latest}\n`; message += ` Type: ${pkg.type}\n\n`; }); message += "Run 'npm update' to update to wanted versions or 'npm install <package>@latest' for latest versions."; } else if (outputFormat === "summary") { const depTypes = outdatedPackages.reduce((acc, pkg) => { acc[pkg.type] = (acc[pkg.type] || 0) + 1; return acc; }, {} as Record<string, number>); message += "\n\nBreakdown by type:\n"; Object.entries(depTypes).forEach(([type, count]) => { message += `- ${type}: ${count}\n`; }); } } let result = `# NPM Outdated Check Results\n\n**Project:** ${packageJsonPath}\n**Total Packages Checked:** ${Object.keys(outdatedData).length}\n\n`; if (outputFormat === "raw") { result += `**Raw Output:**\n\`\`\`\n${rawOutput}\n\`\`\`\n\n`; } result += message; return { content: [ { type: "text", text: result } ] }; } catch (error: any) { // npm outdated exits with code 1 when packages are outdated, this is normal if (error.code === 1) { // This is the normal case - packages are outdated let outdatedData: any = {}; let rawOutput = error.stdout || error.stderr || ''; // Try to parse JSON from stdout or stderr const outputToParse = error.stdout || error.stderr || ''; if (outputToParse && outputToParse.trim()) { try { outdatedData = JSON.parse(outputToParse); } catch (parseError) { // If JSON parsing fails, treat as no outdated packages outdatedData = {}; } } // Parse the outdated packages const outdatedPackages: OutdatedPackage[] = []; for (const [packageName, info] of Object.entries(outdatedData)) { if (typeof info === 'object' && info !== null) { const packageInfo = info as any; outdatedPackages.push({ package: packageName, current: packageInfo.current || 'unknown', wanted: packageInfo.wanted || 'unknown', latest: packageInfo.latest || 'unknown', location: packageInfo.location || resolvedPath, type: packageInfo.type || 'dependencies' }); } } const totalOutdated = outdatedPackages.length; const hasOutdated = totalOutdated > 0; let message: string; if (!hasOutdated) { message = "All packages are up to date! 🎉"; } else { message = `Found ${totalOutdated} outdated package${totalOutdated === 1 ? '' : 's'}`; if (outputFormat === "detailed") { message += ":\n\n"; outdatedPackages.forEach(pkg => { message += `📦 ${pkg.package}\n`; message += ` Current: ${pkg.current}\n`; message += ` Wanted: ${pkg.wanted}\n`; message += ` Latest: ${pkg.latest}\n`; message += ` Type: ${pkg.type}\n\n`; }); message += "Run 'npm update' to update to wanted versions or 'npm install <package>@latest' for latest versions."; } else if (outputFormat === "summary") { const depTypes = outdatedPackages.reduce((acc, pkg) => { acc[pkg.type] = (acc[pkg.type] || 0) + 1; return acc; }, {} as Record<string, number>); message += "\n\nBreakdown by type:\n"; Object.entries(depTypes).forEach(([type, count]) => { message += `- ${type}: ${count}\n`; }); } } let result = `# NPM Outdated Check Results\n\n**Project:** ${packageJsonPath}\n**Total Packages Checked:** ${Object.keys(outdatedData).length}\n\n`; if (outputFormat === "raw") { result += `**Raw Output:**\n\`\`\`\n${rawOutput}\n\`\`\`\n\n`; } result += message; return { content: [ { type: "text", text: result } ] }; } let errorMessage = `Failed to check outdated packages: ${error.message}`; if (error.code === 'ENOENT') { errorMessage = "npm command not found. Please ensure npm is installed and available in your PATH."; } else if (error.message.includes('timeout')) { errorMessage = "npm outdated command timed out. The operation took too long to complete."; } else if (error.message.includes('ENOTDIR') || error.message.includes('ENOENT')) { errorMessage = `Invalid project directory: "${resolvedPath}"`; } throw new McpError(ErrorCode.InternalError, errorMessage); } }
  • Defines the tool metadata including name, description, and input schema for validation.
    export const checkOutdatedTool = { name: "check_outdated", description: "Check for outdated npm packages in package.json using 'npm outdated'. Analyzes the current project's dependencies and shows which packages have newer versions available. Requires npm to be installed and accessible from the command line.", inputSchema: { type: "object", properties: { projectPath: { type: "string", description: "Path to the directory containing package.json. Defaults to the first allowed directory if not specified." }, includeDevDependencies: { type: "boolean", description: "Whether to include dev dependencies in the check", default: true }, outputFormat: { type: "string", enum: ["detailed", "summary", "raw"], description: "Format of the output: detailed (full info), summary (counts only), or raw (npm command output)", default: "detailed" } }, additionalProperties: false } };
  • src/index.ts:33-44 (registration)
    Registers the checkOutdatedTool in the list of available tools returned by ListToolsRequestSchema.
    server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ exploreProjectTool, listAllowedTool, searchTool, renameFileTool, deleteFileTool, checkOutdatedTool ] }; });
  • src/index.ts:68-69 (registration)
    Registers the handler for the 'check_outdated' tool in the CallToolRequestSchema switch dispatcher.
    case "check_outdated": return await handleCheckOutdated(args, ALLOWED_DIRECTORIES);
  • Imports the tool definition and handler from the check-outdated module.
    import { checkOutdatedTool, handleCheckOutdated } from './check-outdated.js';

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MausRundung362/mcp-explorer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server