leanix-pathfinder-mcp-server
Version:
MCP Server for LeanIX Pathfinder API - Enterprise Architecture Management Platform
176 lines • 6.22 kB
JavaScript
export class LeanIXClient {
config;
token = null;
constructor(config) {
this.config = config;
}
async ensureValidToken() {
if (this.token && this.isTokenValid()) {
return;
}
try {
const credentials = `${this.config.clientId}:${this.config.clientSecret}`;
const encodedCredentials = btoa(credentials);
const response = await fetch(`${this.config.baseUrl}/services/mtm/v1/oauth2/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': `Basic ${encodedCredentials}`
},
body: 'grant_type=client_credentials'
});
if (!response.ok) {
throw new Error(`OAuth authentication failed: ${response.status} ${response.statusText}`);
}
const tokenData = await response.json();
this.token = {
...tokenData,
expires_at: Date.now() + (tokenData.expires_in * 1000) - 60000 // 1 minute buffer
};
}
catch (error) {
throw new Error(`OAuth authentication failed: ${error.message}`);
}
}
isTokenValid() {
if (!this.token || !this.token.expires_at) {
return false;
}
return Date.now() < this.token.expires_at;
}
async makeRequest(method, url, config) {
await this.ensureValidToken();
const fullUrl = url.startsWith('http') ? url : `${this.config.baseUrl}${url}`;
const headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
...config?.headers
};
if (this.token) {
headers.Authorization = `Bearer ${this.token.access_token}`;
}
const fetchConfig = {
method,
headers,
};
if (config?.body && (method === 'POST' || method === 'PUT' || method === 'PATCH' || method === 'DELETE')) {
fetchConfig.body = typeof config.body === 'string' ? config.body : JSON.stringify(config.body);
}
const response = await fetch(fullUrl, fetchConfig);
let data;
const contentType = response.headers.get('content-type');
if (contentType?.includes('application/json')) {
data = await response.json();
}
else {
data = await response.text();
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${data?.errorMessage || data || response.statusText}`);
}
const responseHeaders = {};
response.headers.forEach((value, key) => {
responseHeaders[key] = value;
});
return {
data,
status: response.status,
headers: responseHeaders
};
}
async get(url, config) {
return this.makeRequest('GET', url, config);
}
async post(url, data, config) {
return this.makeRequest('POST', url, { ...config, body: data });
}
async put(url, data, config) {
return this.makeRequest('PUT', url, { ...config, body: data });
}
async patch(url, data, config) {
return this.makeRequest('PATCH', url, { ...config, body: data });
}
async delete(url, config) {
return this.makeRequest('DELETE', url, config);
}
// Utility method for handling multipart form data
async postMultipart(url, formData, config) {
await this.ensureValidToken();
const fullUrl = url.startsWith('http') ? url : `${this.config.baseUrl}${url}`;
const headers = {
'Accept': 'application/json',
...config?.headers
};
if (this.token) {
headers.Authorization = `Bearer ${this.token.access_token}`;
}
const response = await fetch(fullUrl, {
method: 'POST',
headers,
body: formData
});
let data;
const contentType = response.headers.get('content-type');
if (contentType?.includes('application/json')) {
data = await response.json();
}
else {
data = await response.text();
}
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${data?.errorMessage || data || response.statusText}`);
}
const responseHeaders = {};
response.headers.forEach((value, key) => {
responseHeaders[key] = value;
});
return {
data,
status: response.status,
headers: responseHeaders
};
}
// Utility method for downloading files
async downloadFile(url, config) {
await this.ensureValidToken();
const fullUrl = url.startsWith('http') ? url : `${this.config.baseUrl}${url}`;
const headers = {
...config?.headers
};
if (this.token) {
headers.Authorization = `Bearer ${this.token.access_token}`;
}
const response = await fetch(fullUrl, {
method: 'GET',
headers
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
return response;
}
// Method to set workspace context
setWorkspaceId(workspaceId) {
this.config.workspaceId = workspaceId;
}
getWorkspaceId() {
return this.config.workspaceId;
}
// Helper method to build query parameters
buildQueryParams(params) {
const searchParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== null) {
if (Array.isArray(value)) {
value.forEach(v => searchParams.append(key, String(v)));
}
else {
searchParams.append(key, String(value));
}
}
}
const queryString = searchParams.toString();
return queryString ? `?${queryString}` : '';
}
}
//# sourceMappingURL=client.js.map