knip-mcp-server
Version:
MCP server for knip.dev integration to help AI agents identify and clean up unused code
150 lines • 6.59 kB
JavaScript
import { KnipFixIssuesInputSchema } from '../types/index.js';
export function createKnipFixIssuesTool(knipClient, config) {
return {
name: 'knip_fix_issues',
description: 'Automatically fix common knip issues like unused imports and files',
inputSchema: {
type: 'object',
properties: {
projectPath: {
type: 'string',
description: 'Path to the project to fix (defaults to current directory)',
},
issueTypes: {
type: 'array',
items: {
type: 'string',
enum: ['files', 'imports', 'exports', 'dependencies'],
},
default: ['imports'],
description: 'Types of issues to fix automatically',
},
dryRun: {
type: 'boolean',
default: true,
description: 'Run in dry-run mode (no files are modified)',
},
createBackup: {
type: 'boolean',
default: true,
description: 'Create backups before making changes',
},
interactive: {
type: 'boolean',
default: false,
description: 'Ask for confirmation before each fix (not supported in MCP)',
},
maxFiles: {
type: 'number',
default: 25,
description: 'Maximum number of files to process in one operation',
},
},
},
execute: async (args) => {
try {
const input = KnipFixIssuesInputSchema.parse(args);
const results = {
success: true,
dryRun: input.dryRun,
fixed: {
files: [],
imports: [],
exports: [],
dependencies: [],
},
errors: [],
};
// Get analysis results
const analysis = await knipClient.scan();
// Fix unused imports
if (input.issueTypes?.includes('imports')) {
const unusedImports = analysis.imports || {};
const filesToProcess = Object.keys(unusedImports).slice(0, input.maxFiles || 25);
for (const filePath of filesToProcess) {
try {
const result = await knipClient.removeUnusedImports(filePath, {
dryRun: input.dryRun,
createBackup: input.createBackup,
});
if (result.success) {
results.fixed.imports.push({
filePath,
removedImports: result.removed_imports,
backedUp: result.backed_up,
});
}
else {
results.errors.push({
type: 'import',
filePath,
error: result.error,
});
}
}
catch (error) {
results.errors.push({
type: 'import',
filePath,
error: error instanceof Error ? error.message : String(error),
});
}
}
}
// Fix unused files
if (input.issueTypes?.includes('files') && config.enableSafeMode !== false) {
const unusedFiles = (analysis.files || []).slice(0, input.maxFiles || 25);
try {
const result = await knipClient.removeUnusedFiles(unusedFiles, {
dryRun: input.dryRun,
createBackup: input.createBackup,
});
results.fixed.files = result.removed;
if (result.errors.length > 0) {
results.errors.push(...result.errors.map((e) => ({
type: 'file',
filePath: e.file,
error: e.error,
})));
}
}
catch (error) {
results.errors.push({
type: 'file',
error: error instanceof Error ? error.message : String(error),
});
}
}
// Note: exports and dependencies fixes would require more sophisticated tooling
if (input.issueTypes?.includes('exports')) {
results.fixed.exports = [];
results.errors.push({
type: 'export',
error: 'Automatic export removal not yet implemented - requires AST analysis',
});
}
if (input.issueTypes?.includes('dependencies')) {
results.fixed.dependencies = [];
results.errors.push({
type: 'dependency',
error: 'Automatic dependency removal not yet implemented - requires package.json modification',
});
}
// Calculate summary
results.summary = {
totalFixed: Object.values(results.fixed).reduce((sum, items) => sum + items.length, 0),
totalErrors: results.errors.length,
issueTypes: input.issueTypes,
};
return results;
}
catch (error) {
return {
success: false,
error: error instanceof Error ? error.message : String(error),
};
}
},
};
}
//# sourceMappingURL=knip-fix-issues.js.map