sonatype-mcp
Version:
Model Context Protocol server for Sonatype Nexus Repository Manager
170 lines (169 loc) • 5.28 kB
JavaScript
import axios from 'axios';
import { createAuthHeaders, validateCredentials } from '../utils/auth.js';
import { handleNexusError, AuthenticationError, ConfigurationError } from '../utils/errors.js';
/**
* Nexus Repository Manager REST API client
*/
export class NexusClient {
client;
config;
constructor(config) {
this.config = config;
// Validate configuration
if (!validateCredentials(config)) {
throw new ConfigurationError('Invalid Nexus credentials: username and password are required');
}
// Create axios instance with default configuration
this.client = axios.create({
baseURL: config.nexus.baseUrl,
timeout: config.nexus.timeout,
headers: createAuthHeaders(config),
validateStatus: () => true, // We'll handle all status codes manually
...(config.nexus.validateSsl === false && {
httpsAgent: new (require('https').Agent)({
rejectUnauthorized: false
})
})
});
// Request interceptor for logging
this.client.interceptors.request.use((config) => {
console.error(`Making request to: ${config.method?.toUpperCase()} ${config.url}`);
return config;
}, (error) => {
console.error('Request interceptor error:', error);
return Promise.reject(error);
});
// Response interceptor for error handling
this.client.interceptors.response.use((response) => {
console.error(`Response: ${response.status} ${response.statusText}`);
return response;
}, (error) => {
console.error('Response interceptor error:', error);
return Promise.reject(error);
});
}
/**
* Test the connection to Nexus
*/
async testConnection() {
try {
const response = await this.client.get('/service/rest/v1/status/check');
return response.status === 200;
}
catch (error) {
console.error('Connection test failed:', error);
return false;
}
}
/**
* Make a GET request to Nexus API
*/
async get(endpoint, options = {}) {
try {
const response = await this.client.get(endpoint, {
...options,
headers: {
...createAuthHeaders(this.config),
...options.headers
}
});
if (response.status >= 400) {
throw { response };
}
return response.data;
}
catch (error) {
handleNexusError(error);
}
}
/**
* Make a POST request to Nexus API
*/
async post(endpoint, data, options = {}) {
if (this.config.server.readOnly) {
throw new AuthenticationError('Write operations are disabled in read-only mode');
}
try {
const response = await this.client.post(endpoint, data, {
...options,
headers: {
...createAuthHeaders(this.config),
...options.headers
}
});
if (response.status >= 400) {
throw { response };
}
return response.data;
}
catch (error) {
handleNexusError(error);
}
}
/**
* Make a PUT request to Nexus API
*/
async put(endpoint, data, options = {}) {
if (this.config.server.readOnly) {
throw new AuthenticationError('Write operations are disabled in read-only mode');
}
try {
const response = await this.client.put(endpoint, data, {
...options,
headers: {
...createAuthHeaders(this.config),
...options.headers
}
});
if (response.status >= 400) {
throw { response };
}
return response.data;
}
catch (error) {
handleNexusError(error);
}
}
/**
* Make a DELETE request to Nexus API
*/
async delete(endpoint, options = {}) {
if (this.config.server.readOnly) {
throw new AuthenticationError('Write operations are disabled in read-only mode');
}
try {
const response = await this.client.delete(endpoint, {
...options,
headers: {
...createAuthHeaders(this.config),
...options.headers
}
});
if (response.status >= 400) {
throw { response };
}
return response.data;
}
catch (error) {
handleNexusError(error);
}
}
/**
* Get server information
*/
async getServerInfo() {
return this.get('/service/rest/v1/status');
}
/**
* Get read-only mode status
*/
isReadOnly() {
return this.config.server.readOnly;
}
/**
* Get base URL
*/
getBaseUrl() {
return this.config.nexus.baseUrl;
}
}