@hackle-io/hackle-mcp
Version:
Model Context Protocol server for Hackle
90 lines (89 loc) • 2.97 kB
JavaScript
const BASE_URL = 'https://admin-api.hackle.io';
const ENVIRONMENT_KEY = process.env.ENVIRONMENT_KEY || 'PRODUCTION';
const API_KEY = process.env.API_KEY || '';
if (!API_KEY) {
console.warn('API_KEY environment variable is not set');
}
const DEFAULT_HEADERS = {
accept: 'application/json',
'Content-Type': 'application/json',
'X-HACKLE-ADMIN-API-KEY': API_KEY,
'X-HACKLE-TIME-ZONE': Intl.DateTimeFormat().resolvedOptions().timeZone,
};
class WebClient {
static async request(method, path, options = {}) {
const url = new URL(`${BASE_URL}${path}`);
url.searchParams.set('environmentKey', ENVIRONMENT_KEY);
if (typeof fetch === 'undefined') {
return WebClient.fetchFallback(method, url, options);
}
const response = await fetch(url, {
method,
...options,
headers: {
...DEFAULT_HEADERS,
...options.headers,
},
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Hackle API error! status: ${response.status} - ${errorText}`);
}
return (await response.json());
}
static async fetchFallback(method, url, options) {
const { default: nodeFetch } = await import('node-fetch');
const { body, ...otherOptions } = options;
if (body !== null && body !== undefined && typeof body !== 'string') {
throw new Error(`[ERROR] Invalid body type: ${body}`);
}
const response = await nodeFetch(url, {
method,
headers: {
...DEFAULT_HEADERS,
...options.headers,
},
body: body,
...otherOptions,
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Hackle API error! status: ${response.status} - ${errorText}`);
}
return (await response.json());
}
static async get(path, options) {
return this.request('GET', path, options);
}
static async post(path, body, options) {
return this.request('POST', path, {
...options,
body: JSON.stringify(body),
headers: {
...options?.headers,
},
});
}
static async put(path, body, options) {
return this.request('PUT', path, {
...options,
body: JSON.stringify(body),
headers: {
...options?.headers,
},
});
}
static async delete(path, options) {
return this.request('DELETE', path, options);
}
static async patch(path, body, options) {
return this.request('PATCH', path, {
...options,
body: JSON.stringify(body),
headers: {
...options?.headers,
},
});
}
}
export default WebClient;