@brianveltman/sonatype-mcp
Version:
Model Context Protocol server for Sonatype Nexus Repository Manager
126 lines • 6.79 kB
JavaScript
import { z } from 'zod';
import FormData from 'form-data';
import fs from 'fs/promises';
import path from 'path';
import { validateInput } from '../../utils/validation.js';
import { formatMCPError } from '../../utils/errors.js';
const uploadComponentSchema = z.object({
repository: z.string().describe('The repository to upload to'),
format: z.enum(['maven2', 'npm', 'pypi', 'docker', 'raw', 'helm', 'nuget', 'rubygems']).describe('Repository format'),
file: z.string().describe('Path to the file to upload'),
groupId: z.string().optional().describe('Maven group ID (e.g., com.example) - required for maven2'),
artifactId: z.string().optional().describe('Maven artifact ID - required for maven2'),
version: z.string().optional().describe('Component version - required for maven2'),
packaging: z.string().optional().describe('Packaging type (e.g., jar, war, pom)'),
generatePom: z.boolean().optional().describe('Whether to generate a POM file'),
classifier: z.string().optional().describe('Classifier for the artifact'),
directory: z.string().optional().describe('Directory path in the repository - required for raw'),
filename: z.string().optional().describe('Filename to use in the repository')
});
export function createUploadComponentTool(componentService) {
return {
name: 'nexus_upload_component',
description: 'Upload a component to a Nexus repository',
inputSchema: {
type: 'object',
properties: {
repository: { type: 'string', description: 'The repository to upload to' },
format: {
type: 'string',
enum: ['maven2', 'npm', 'pypi', 'docker', 'raw', 'helm', 'nuget', 'rubygems'],
description: 'Repository format'
},
file: { type: 'string', description: 'Path to the file to upload' },
groupId: { type: 'string', description: 'Maven group ID - required for maven2' },
artifactId: { type: 'string', description: 'Maven artifact ID - required for maven2' },
version: { type: 'string', description: 'Component version - required for maven2' },
packaging: { type: 'string', description: 'Packaging type (jar, war, pom)' },
generatePom: { type: 'boolean', description: 'Generate POM file' },
classifier: { type: 'string', description: 'Classifier (sources, javadoc)' },
directory: { type: 'string', description: 'Directory path - required for raw' },
filename: { type: 'string', description: 'Filename in repository' }
},
required: ['repository', 'format', 'file']
},
handler: async (params) => {
try {
const validParams = validateInput(uploadComponentSchema, params);
if (validParams.format === 'maven2' && (!validParams.groupId || !validParams.artifactId || !validParams.version)) {
throw new Error('Maven uploads require groupId, artifactId, and version');
}
if (validParams.format === 'raw' && !validParams.directory) {
throw new Error('Raw uploads require directory parameter');
}
try {
await fs.access(validParams.file);
}
catch {
throw new Error(`File not found: ${validParams.file}`);
}
const form = new FormData();
const fileBuffer = await fs.readFile(validParams.file);
const fileName = path.basename(validParams.file);
switch (validParams.format) {
case 'maven2':
form.append('maven2.groupId', validParams.groupId);
form.append('maven2.artifactId', validParams.artifactId);
form.append('maven2.version', validParams.version);
if (validParams.packaging)
form.append('maven2.packaging', validParams.packaging);
if (validParams.generatePom !== undefined)
form.append('maven2.generate-pom', validParams.generatePom.toString());
form.append('maven2.asset1', fileBuffer, fileName);
form.append('maven2.asset1.extension', path.extname(fileName).slice(1) || 'jar');
if (validParams.classifier)
form.append('maven2.asset1.classifier', validParams.classifier);
break;
case 'raw':
form.append('raw.directory', validParams.directory);
form.append('raw.asset1', fileBuffer, fileName);
form.append('raw.asset1.filename', validParams.filename || fileName);
break;
case 'npm':
form.append('npm.asset', fileBuffer, fileName);
break;
case 'pypi':
form.append('pypi.asset', fileBuffer, fileName);
break;
case 'docker':
form.append('docker.asset', fileBuffer, fileName);
break;
case 'helm':
form.append('helm.asset', fileBuffer, fileName);
break;
case 'nuget':
form.append('nuget.asset', fileBuffer, fileName);
break;
case 'rubygems':
form.append('rubygems.asset', fileBuffer, fileName);
break;
}
const result = await componentService.uploadComponent(validParams.repository, form);
return {
content: [{
type: 'text',
text: JSON.stringify({
success: true,
component: result,
message: `Successfully uploaded component to ${validParams.repository}`
}, null, 2)
}]
};
}
catch (error) {
const mcpError = formatMCPError(error);
return {
content: [{
type: 'text',
text: `Error: ${mcpError.message}`
}],
isError: true
};
}
}
};
}
//# sourceMappingURL=upload-component.js.map