@brianveltman/sonatype-mcp
Version:
Model Context Protocol server for Sonatype Nexus Repository Manager
158 lines • 5.29 kB
JavaScript
import axios from 'axios';
import { createAuthHeaders, validateCredentials } from '../utils/auth.js';
import { handleNexusError, AuthenticationError } from '../utils/errors.js';
export class NexusClient {
client;
config;
constructor(config) {
this.config = config;
const headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
};
if (validateCredentials(config)) {
Object.assign(headers, createAuthHeaders(config));
}
this.client = axios.create({
baseURL: config.nexus.baseUrl,
timeout: config.nexus.timeout,
headers,
validateStatus: () => true,
...(config.nexus.validateSsl === false && {
httpsAgent: new (require('https').Agent)({
rejectUnauthorized: false
})
})
});
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);
});
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);
});
}
hasCredentials() {
return validateCredentials(this.config);
}
ensureCredentials() {
if (!this.hasCredentials()) {
throw new AuthenticationError('Nexus credentials not configured. Please set NEXUS_USERNAME and NEXUS_PASSWORD environment variables.');
}
}
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;
}
}
async get(endpoint, options = {}) {
try {
if (!endpoint.includes('/status/check') && !endpoint.includes('/status/writable')) {
this.ensureCredentials();
}
const headers = { ...options.headers };
if (this.hasCredentials()) {
Object.assign(headers, createAuthHeaders(this.config));
}
const response = await this.client.get(endpoint, {
...options,
headers
});
if (response.status >= 400) {
throw { response };
}
return response.data;
}
catch (error) {
handleNexusError(error);
}
}
async post(endpoint, data, options = {}) {
if (this.config.server.readOnly) {
throw new AuthenticationError('Write operations are disabled in read-only mode');
}
this.ensureCredentials();
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);
}
}
async put(endpoint, data, options = {}) {
if (this.config.server.readOnly) {
throw new AuthenticationError('Write operations are disabled in read-only mode');
}
this.ensureCredentials();
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);
}
}
async delete(endpoint, options = {}) {
if (this.config.server.readOnly) {
throw new AuthenticationError('Write operations are disabled in read-only mode');
}
this.ensureCredentials();
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);
}
}
async getServerInfo() {
return this.get('/service/rest/v1/status');
}
isReadOnly() {
return this.config.server.readOnly;
}
getBaseUrl() {
return this.config.nexus.baseUrl;
}
}
//# sourceMappingURL=nexus-client.js.map