facebook-ads-mcp-server
Version:
Universal Facebook Ads Server - Supports MCP, OpenAI Function Calling, and Gemini Function Calling
115 lines (96 loc) • 3.29 kB
JavaScript
import axios from 'axios';
import { TokenStorage } from '../auth/token-storage.js';
export class FacebookAPIClient {
constructor() {
this.baseURL = process.env.FACEBOOK_BASE_URL || 'https://graph.facebook.com';
this.version = process.env.FACEBOOK_API_VERSION || 'v23.0';
this.accessToken = null;
this.client = axios.create({
baseURL: `${this.baseURL}/${this.version}`,
timeout: 30000,
});
}
async getAccessToken() {
// Try stored token first
const storedToken = await TokenStorage.getToken();
if (storedToken) {
this.accessToken = storedToken;
return storedToken;
}
// Only allow hardcoded token for testing purposes
const isTestMode = process.env.NODE_ENV === 'test' || process.env.FACEBOOK_ALLOW_HARDCODED_TOKEN === 'true';
if (isTestMode && process.env.FACEBOOK_ACCESS_TOKEN) {
console.error('⚠️ Using hardcoded access token (TEST MODE ONLY)');
this.accessToken = process.env.FACEBOOK_ACCESS_TOKEN;
return this.accessToken;
}
throw new Error('No Facebook access token available. Please run facebook_login to authenticate.');
}
async makeRequest(endpoint, methodOrParams = 'GET', params = {}) {
try {
// Handle backward compatibility: makeRequest(endpoint, params) or makeRequest(endpoint, method, params)
let method = 'GET';
let actualParams = {};
if (typeof methodOrParams === 'string') {
// New format: makeRequest(endpoint, method, params)
method = methodOrParams;
actualParams = params;
} else {
// Old format: makeRequest(endpoint, params)
method = 'GET';
actualParams = methodOrParams || {};
}
// Ensure we have a valid token
const accessToken = await this.getAccessToken();
const config = {
method: method.toLowerCase(),
url: endpoint,
};
if (method.toUpperCase() === 'GET') {
config.params = {
access_token: accessToken,
...actualParams,
};
} else {
config.data = {
access_token: accessToken,
...actualParams,
};
}
const response = await this.client.request(config);
return response.data;
} catch (error) {
this.handleAPIError(error);
}
}
async makeRequestFromFullURL(url) {
try {
const response = await axios.get(url);
return response.data;
} catch (error) {
this.handleAPIError(error);
}
}
async makeBatchRequest(batchRequests) {
try {
const accessToken = await this.getAccessToken();
const response = await this.client.post('/', {
access_token: accessToken,
batch: JSON.stringify(batchRequests)
});
return response.data;
} catch (error) {
this.handleAPIError(error);
}
}
handleAPIError(error) {
if (error.response?.data?.error) {
const fbError = error.response.data.error;
throw new Error(`Facebook API Error: ${fbError.message} (Code: ${fbError.code})`);
}
if (error.code === 'ECONNABORTED') {
throw new Error('Request timeout - Facebook API took too long to respond');
}
throw new Error(`API Request failed: ${error.message}`);
}
}