=== NEW SERVERS ADDED (7) === - servers/closebot — 119 tools, 14 modules, 4,656 lines TS (Stage 7) - servers/google-console — Google Search Console MCP (Stage 7) - servers/meta-ads — Meta/Facebook Ads MCP (Stage 8) - servers/twilio — Twilio communications MCP (Stage 8) - servers/competitor-research — Competitive intel MCP (Stage 6) - servers/n8n-apps — n8n workflow MCP apps (Stage 6) - servers/reonomy — Commercial real estate MCP (Stage 1) === FACTORY INFRASTRUCTURE ADDED === - infra/factory-tools — mcp-jest, mcp-validator, mcp-add, MCP Inspector - 60 test configs, 702 auto-generated test cases - All 30 servers score 100/100 protocol compliance - infra/command-center — Pipeline state, operator playbook, dashboard config - infra/factory-reviews — Automated eval reports === DOCS ADDED === - docs/MCP-FACTORY.md — Factory overview - docs/reports/ — 5 pipeline evaluation reports - docs/research/ — Browser MCP research === RULES ESTABLISHED === - CONTRIBUTING.md — All MCP work MUST go in this repo - README.md — Full inventory of 37 servers + infra docs - .gitignore — Updated for Python venvs TOTAL: 37 MCP servers + full factory pipeline in one repo. This is now the single source of truth for all MCP work.
213 lines
6.4 KiB
JavaScript
213 lines
6.4 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { config } from 'dotenv';
|
|
import { AuthManager } from './auth/oauth.js';
|
|
import { MetaApiClient } from './client/meta-client.js';
|
|
import { RateLimiter } from './client/rate-limiter.js';
|
|
import {
|
|
createMcpServer,
|
|
connectServer,
|
|
ToolRegistry,
|
|
ModuleRegistry,
|
|
createGatewayTool,
|
|
} from './server.js';
|
|
|
|
// Import Tier 1 (core) tool modules
|
|
import { registerAccountTools } from './tools/account.js';
|
|
import { registerCampaignTools } from './tools/campaigns.js';
|
|
import { registerAdSetTools } from './tools/ad-sets.js';
|
|
import { registerAdTools } from './tools/ads.js';
|
|
|
|
/**
|
|
* Main entry point for Meta Ads MCP server
|
|
*/
|
|
async function main() {
|
|
// Load environment variables
|
|
config();
|
|
|
|
const accessToken = process.env.META_ACCESS_TOKEN;
|
|
const appId = process.env.META_APP_ID;
|
|
const appSecret = process.env.META_APP_SECRET;
|
|
const apiVersion = process.env.META_API_VERSION || 'v21.0';
|
|
|
|
if (!accessToken) {
|
|
console.error('Error: META_ACCESS_TOKEN environment variable is required');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.error('[MCP] Initializing Meta Ads MCP Server...');
|
|
|
|
// Initialize auth and client
|
|
const authManager = new AuthManager(accessToken, appId, appSecret);
|
|
const rateLimiter = new RateLimiter(5); // Max 5 concurrent requests
|
|
// Cache available for future use
|
|
// const cache = new SimpleCache(1000, 300); // 1000 entries, 5 minute TTL
|
|
const client = new MetaApiClient(authManager, { apiVersion }, rateLimiter);
|
|
|
|
// Validate token on startup
|
|
try {
|
|
console.error('[MCP] Validating access token...');
|
|
const tokenInfo = await authManager.validateToken();
|
|
console.error(`[MCP] Token valid. User ID: ${tokenInfo.userId}, Expires: ${tokenInfo.expiresAt ? new Date(tokenInfo.expiresAt).toISOString() : 'never'}`);
|
|
|
|
// Warn if token expires soon
|
|
if (authManager.isTokenExpired(60)) {
|
|
console.error('[MCP] WARNING: Access token expires within 1 hour. Consider refreshing.');
|
|
}
|
|
} catch (error) {
|
|
console.error(`[MCP] Token validation failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
console.error('[MCP] Server will start but API calls may fail. Please check your META_ACCESS_TOKEN.');
|
|
}
|
|
|
|
// Create tool and module registries
|
|
const toolRegistry = new ToolRegistry(client);
|
|
const moduleRegistry = new ModuleRegistry(toolRegistry);
|
|
|
|
// Register Tier 1 (core) modules - loaded immediately
|
|
console.error('[MCP] Registering core modules (Tier 1)...');
|
|
|
|
moduleRegistry.registerModule({
|
|
category: 'account',
|
|
tier: 'core',
|
|
loaded: false,
|
|
register: registerAccountTools,
|
|
});
|
|
|
|
moduleRegistry.registerModule({
|
|
category: 'campaigns',
|
|
tier: 'core',
|
|
loaded: false,
|
|
register: registerCampaignTools,
|
|
});
|
|
|
|
moduleRegistry.registerModule({
|
|
category: 'adsets',
|
|
tier: 'core',
|
|
loaded: false,
|
|
register: registerAdSetTools,
|
|
});
|
|
|
|
moduleRegistry.registerModule({
|
|
category: 'ads',
|
|
tier: 'core',
|
|
loaded: false,
|
|
register: registerAdTools,
|
|
});
|
|
|
|
// Load core modules immediately
|
|
await moduleRegistry.loadModule('account');
|
|
await moduleRegistry.loadModule('campaigns');
|
|
await moduleRegistry.loadModule('adsets');
|
|
await moduleRegistry.loadModule('ads');
|
|
|
|
// Register Tier 2 (advanced) modules - lazy loaded via gateway tools
|
|
console.error('[MCP] Registering advanced modules (Tier 2) as gateway tools...');
|
|
|
|
// Analytics module (gateway)
|
|
moduleRegistry.registerModule({
|
|
category: 'analytics',
|
|
tier: 'advanced',
|
|
loaded: false,
|
|
register: async (registry) => {
|
|
// This would be implemented in src/tools/analytics.ts
|
|
// For now, just a placeholder
|
|
console.error('[MCP] Analytics module loaded (placeholder)');
|
|
registry.registerTool({
|
|
name: 'get_insights_placeholder',
|
|
description: 'Placeholder for insights tool',
|
|
inputSchema: require('zod').z.object({}),
|
|
handler: async () => ({
|
|
content: [{ type: 'text', text: 'Analytics module loaded but not yet implemented' }],
|
|
}),
|
|
});
|
|
},
|
|
});
|
|
|
|
toolRegistry.registerTool(
|
|
createGatewayTool(
|
|
'analytics',
|
|
moduleRegistry,
|
|
'Load analytics and insights tools for campaign performance analysis'
|
|
)
|
|
);
|
|
|
|
// Audiences module (gateway)
|
|
moduleRegistry.registerModule({
|
|
category: 'audiences',
|
|
tier: 'advanced',
|
|
loaded: false,
|
|
register: async (registry) => {
|
|
console.error('[MCP] Audiences module loaded (placeholder)');
|
|
registry.registerTool({
|
|
name: 'list_audiences_placeholder',
|
|
description: 'Placeholder for audience tools',
|
|
inputSchema: require('zod').z.object({}),
|
|
handler: async () => ({
|
|
content: [{ type: 'text', text: 'Audiences module loaded but not yet implemented' }],
|
|
}),
|
|
});
|
|
},
|
|
});
|
|
|
|
toolRegistry.registerTool(
|
|
createGatewayTool(
|
|
'audiences',
|
|
moduleRegistry,
|
|
'Load audience management tools for custom audiences, lookalikes, and saved audiences'
|
|
)
|
|
);
|
|
|
|
// Budget optimization module (gateway)
|
|
moduleRegistry.registerModule({
|
|
category: 'budget',
|
|
tier: 'advanced',
|
|
loaded: false,
|
|
register: async (registry) => {
|
|
console.error('[MCP] Budget module loaded (placeholder)');
|
|
registry.registerTool({
|
|
name: 'optimize_budget_placeholder',
|
|
description: 'Placeholder for budget tools',
|
|
inputSchema: require('zod').z.object({}),
|
|
handler: async () => ({
|
|
content: [{ type: 'text', text: 'Budget module loaded but not yet implemented' }],
|
|
}),
|
|
});
|
|
},
|
|
});
|
|
|
|
toolRegistry.registerTool(
|
|
createGatewayTool(
|
|
'budget',
|
|
moduleRegistry,
|
|
'Load budget optimization tools for CBO management and budget recommendations'
|
|
)
|
|
);
|
|
|
|
// Create and connect MCP server
|
|
const server = createMcpServer(toolRegistry);
|
|
|
|
// Graceful shutdown handling
|
|
const shutdown = async () => {
|
|
console.error('[MCP] Shutting down...');
|
|
process.exit(0);
|
|
};
|
|
|
|
process.on('SIGINT', shutdown);
|
|
process.on('SIGTERM', shutdown);
|
|
|
|
// Connect to stdio transport
|
|
await connectServer(server);
|
|
|
|
// Log module status
|
|
const moduleStatus = moduleRegistry.getModuleStatus();
|
|
console.error('[MCP] Module status:', JSON.stringify(moduleStatus, null, 2));
|
|
console.error(`[MCP] Registered ${toolRegistry.getTools().length} tools`);
|
|
console.error('[MCP] Server ready!');
|
|
}
|
|
|
|
// Run the server
|
|
main().catch((error) => {
|
|
console.error('[MCP] Fatal error:', error);
|
|
process.exit(1);
|
|
});
|