@grebyn/toolflow-mcp-server
Version:
MCP server for managing other MCP servers - discover, install, organize into bundles, and automate with workflows. Uses StreamableHTTP transport with dual OAuth/API key authentication.
105 lines • 3.76 kB
JavaScript
/**
* API Client for proxying requests to ToolFlow backend
*
* This client forwards authenticated requests to your Vercel API,
* which handles all Supabase operations with proper credentials.
*/
import { getServerConfig } from '../config/server-config.js';
export class ApiClient {
static apiEndpoint = getServerConfig().apiEndpoint;
/**
* Make an authenticated request to the ToolFlow API proxy
*/
static async proxyRequest(operation, params, context) {
const url = `${this.apiEndpoint}/proxy`;
const headers = {
'Content-Type': 'application/json',
};
// Add authentication - prioritize API key over OAuth token
if (context?.apiKey) {
headers['Authorization'] = `Bearer ${context.apiKey}`;
}
else if (context?.token) {
headers['Authorization'] = `Bearer ${context.token}`;
}
else {
throw new Error('No authentication token or API key provided');
}
const response = await fetch(url, {
method: 'POST',
headers,
body: JSON.stringify({ operation, params })
});
if (!response.ok) {
const error = await response.text();
throw new Error(`API request failed (${response.status}): ${error}`);
}
return response.json();
}
/**
* Bundle operations
*/
static async searchBundles(params, context) {
return this.proxyRequest('searchBundles', params, context);
}
static async createBundle(data, context) {
return this.proxyRequest('createBundle', data, context);
}
static async updateBundle(bundleId, updates, context) {
return this.proxyRequest('updateBundle', { bundleId, ...updates }, context);
}
static async getBundleConfig(bundleId, context) {
return this.proxyRequest('getBundleConfig', { bundleId }, context);
}
/**
* Workflow operations
*/
static async searchWorkflows(params, context) {
return this.proxyRequest('searchWorkflows', params, context);
}
static async createWorkflow(data, context) {
return this.proxyRequest('createWorkflow', data, context);
}
static async updateWorkflow(workflowId, updates, context) {
return this.proxyRequest('updateWorkflow', { workflowId, ...updates }, context);
}
static async getWorkflow(workflowId, context) {
return this.proxyRequest('getWorkflow', { workflowId }, context);
}
/**
* Log MCP tool execution
*/
static async logExecution(logData, context) {
try {
const url = `${this.apiEndpoint}/mcp/logs`;
const headers = {
'Content-Type': 'application/json',
};
// Add authentication
if (context?.apiKey) {
headers['Authorization'] = `Bearer ${context.apiKey}`;
}
else if (context?.token) {
headers['Authorization'] = `Bearer ${context.token}`;
}
else {
console.error('No authentication for logging');
return;
}
// Fire and forget - don't await
fetch(url, {
method: 'POST',
headers,
body: JSON.stringify(logData)
}).catch(error => {
// Silently fail - logging should never break tool execution
console.error('Failed to send log:', error);
});
}
catch (error) {
// Silently fail - logging should never break tool execution
console.error('Logging error:', error);
}
}
}
//# sourceMappingURL=api-client.js.map