UNPKG

@rashidazarang/aptly-mcp

Version:

Model Context Protocol server for Aptly package repository management - enables AI assistants to manage Debian repositories

280 lines 12.5 kB
import { addPackagesSchema, searchPackagesSchema, formatValidationError } from '../utils/validation.js'; import { z } from 'zod'; export function createPackageTools(client) { return [ { name: 'aptly_list_packages', description: 'List packages in a repository', inputSchema: { type: 'object', properties: { repoName: { type: 'string', description: 'Name of the repository to list packages from' }, query: { type: 'string', description: 'Optional search query to filter packages' } }, required: ['repoName'] } }, { name: 'aptly_search_packages', description: 'Search for packages across repositories or in a specific repository', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query (package name, description, etc.)' }, repoName: { type: 'string', description: 'Optional repository name to search within (if not provided, searches all repositories)' }, format: { type: 'string', enum: ['compact', 'details'], description: 'Output format for search results', default: 'compact' } }, required: ['query'] } }, { name: 'aptly_add_packages', description: 'Add packages to a repository from uploaded files', inputSchema: { type: 'object', properties: { repoName: { type: 'string', description: 'Name of the repository to add packages to' }, directory: { type: 'string', description: 'Upload directory containing the package files' }, files: { type: 'array', items: { type: 'string' }, description: 'Optional list of specific files to add (if not provided, adds all files from directory)' } }, required: ['repoName', 'directory'] } }, { name: 'aptly_list_uploaded_files', description: 'List uploaded files available for adding to repositories', inputSchema: { type: 'object', properties: { directory: { type: 'string', description: 'Optional directory name to list files from (if not provided, lists all directories)' } }, required: [] } }, { name: 'aptly_delete_uploaded_files', description: 'Delete uploaded files or directories', inputSchema: { type: 'object', properties: { directory: { type: 'string', description: 'Directory name to delete' }, filename: { type: 'string', description: 'Optional specific filename to delete (if not provided, deletes entire directory)' } }, required: ['directory'] } } ]; } export async function handlePackageTool(client, name, arguments_) { try { switch (name) { case 'aptly_list_packages': { const args = z.object({ repoName: z.string(), query: z.string().optional() }).parse(arguments_); const packages = await client.listPackages(args.repoName, args.query); if (packages.length === 0) { return { content: [{ type: 'text', text: args.query ? `No packages found matching '${args.query}' in repository '${args.repoName}'.` : `Repository '${args.repoName}' contains no packages.` }] }; } const packageList = packages.map(pkg => { return `• ${pkg.Package || pkg.Key} (${pkg.Version || 'unknown version'})` + (pkg.Architecture ? ` [${pkg.Architecture}]` : '') + (pkg.Description ? ` - ${pkg.Description.substring(0, 80)}${pkg.Description.length > 80 ? '...' : ''}` : ''); }).join('\n'); return { content: [{ type: 'text', text: `Found ${packages.length} package(s) in repository '${args.repoName}':\n\n${packageList}` }] }; } case 'aptly_search_packages': { const args = searchPackagesSchema.parse(arguments_); if (args.repoName) { // Search in specific repository const packages = await client.listPackages(args.repoName, args.query); if (packages.length === 0) { return { content: [{ type: 'text', text: `No packages found matching '${args.query}' in repository '${args.repoName}'.` }] }; } const packageList = packages.map(pkg => { if (args.format === 'details') { return `Package: ${pkg.Package || pkg.Key}\n` + `Version: ${pkg.Version || 'unknown'}\n` + `Architecture: ${pkg.Architecture || 'unknown'}\n` + `Description: ${pkg.Description || 'No description'}\n` + `Maintainer: ${pkg.Maintainer || 'Unknown'}\n` + `Size: ${pkg.Size || 'Unknown'} bytes\n`; } else { return `• ${pkg.Package || pkg.Key} (${pkg.Version || 'unknown'})` + (pkg.Architecture ? ` [${pkg.Architecture}]` : ''); } }).join('\n'); return { content: [{ type: 'text', text: `Found ${packages.length} package(s) matching '${args.query}' in repository '${args.repoName}':\n\n${packageList}` }] }; } else { // Search across all repositories const repos = await client.listRepositories(); let totalPackages = 0; let results = []; for (const repo of repos) { try { const packages = await client.listPackages(repo.Name, args.query); if (packages.length > 0) { totalPackages += packages.length; results.push(`\nRepository: ${repo.Name} (${packages.length} matches)`); const packageList = packages.map(pkg => { return ` • ${pkg.Package || pkg.Key} (${pkg.Version || 'unknown'})` + (pkg.Architecture ? ` [${pkg.Architecture}]` : ''); }).join('\n'); results.push(packageList); } } catch (error) { // Skip repositories that can't be searched continue; } } if (totalPackages === 0) { return { content: [{ type: 'text', text: `No packages found matching '${args.query}' across all repositories.` }] }; } return { content: [{ type: 'text', text: `Found ${totalPackages} package(s) matching '${args.query}' across ${repos.length} repositories:${results.join('\n')}` }] }; } } case 'aptly_add_packages': { const args = addPackagesSchema.parse(arguments_); await client.addPackages(args.repoName, args.directory, args.files); const fileCount = args.files ? args.files.length : 'all'; return { content: [{ type: 'text', text: `Successfully added ${fileCount} package(s) from directory '${args.directory}' to repository '${args.repoName}'.` }] }; } case 'aptly_list_uploaded_files': { const args = z.object({ directory: z.string().optional() }).parse(arguments_); const files = await client.listUploadedFiles(args.directory); if (Object.keys(files).length === 0) { return { content: [{ type: 'text', text: args.directory ? `No files found in directory '${args.directory}'.` : 'No uploaded files found.' }] }; } let result = ''; for (const [dir, fileList] of Object.entries(files)) { result += `\nDirectory: ${dir}\n`; if (fileList.length === 0) { result += ' (empty)\n'; } else { fileList.forEach(file => { result += ` • ${file.filename} (${file.size} bytes)\n`; }); } } return { content: [{ type: 'text', text: `Uploaded files:${result}` }] }; } case 'aptly_delete_uploaded_files': { const args = z.object({ directory: z.string(), filename: z.string().optional() }).parse(arguments_); await client.deleteUploadedFiles(args.directory, args.filename); const target = args.filename ? `file '${args.filename}' from directory '${args.directory}'` : `directory '${args.directory}' and all its files`; return { content: [{ type: 'text', text: `Successfully deleted ${target}.` }] }; } default: throw new Error(`Unknown package tool: ${name}`); } } catch (error) { if (error instanceof z.ZodError) { throw new Error(`Validation error: ${formatValidationError(error)}`); } throw error; } } //# sourceMappingURL=package-tools.js.map