UNPKG

flow-nexus

Version:

🚀 AI-Powered Swarm Intelligence Platform - Gamified MCP Development with 70+ Tools

475 lines (430 loc) 13.3 kB
/** * Flow-Nexus MCP Payment Tools * Integrated payment commands for the flow-nexus MCP server */ import Stripe from 'stripe'; import chalk from 'chalk'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || 'sk_test_51S1XHUCW68gTm0lpDgbCw7uVb6cH2WDZkcHn0Q9X9BM5bIPd8MmgdDddvbo8DYdTNk49nlWNvY8GsihEUDuiSYZL00UCjYmYO0', { apiVersion: '2023-10-16', }); /** * Register payment tools with the MCP server */ export function registerPaymentTools(server, supabase) { // Tool: check_balance server.addTool({ name: 'check_balance', description: 'Check current credit balance and auto-refill status', inputSchema: { type: 'object', properties: { user_id: { type: 'string', description: 'User ID (optional, uses current user if not provided)', }, }, }, handler: async (params, context) => { try { const userId = params.user_id || context.user?.id; if (!userId) { return { success: false, error: 'User not authenticated', }; } const { data: profile, error } = await supabase .from('profiles') .select('credits_balance, ruv_credits, auto_refill_enabled, auto_refill_threshold, auto_refill_amount') .eq('id', userId) .single(); if (error) { throw error; } const balance = profile.credits_balance || profile.ruv_credits || 0; const lowBalance = balance < 20; return { success: true, balance: balance, auto_refill_enabled: profile.auto_refill_enabled, auto_refill_threshold: profile.auto_refill_threshold, auto_refill_amount: profile.auto_refill_amount, low_balance_warning: lowBalance, message: `Current balance: ${balance} credits${lowBalance ? ' (⚠️ LOW BALANCE)' : ''}`, }; } catch (error) { return { success: false, error: error.message, }; } }, }); // Tool: create_payment_link server.addTool({ name: 'create_payment_link', description: 'Create a Stripe payment link for purchasing credits', inputSchema: { type: 'object', properties: { amount: { type: 'number', description: 'Amount in USD (minimum $10)', minimum: 10, }, user_id: { type: 'string', description: 'User ID (optional)', }, }, required: ['amount'], }, handler: async (params, context) => { try { const userId = params.user_id || context.user?.id; const amount = params.amount; // Calculate credits (1 USD = 10 credits, with bonuses) let credits = amount * 10; if (amount >= 100) { credits *= 1.1; // 10% bonus } // Get user profile const { data: profile } = await supabase .from('profiles') .select('email, stripe_customer_id') .eq('id', userId) .single(); // Create or get Stripe customer let customerId = profile?.stripe_customer_id; if (!customerId && profile?.email) { const customer = await stripe.customers.create({ email: profile.email, metadata: { user_id: userId }, }); customerId = customer.id; // Update profile await supabase .from('profiles') .update({ stripe_customer_id: customerId }) .eq('id', userId); } // Create product and price const product = await stripe.products.create({ name: `${credits} Flow Credits`, description: `Purchase of ${credits} credits`, }); const price = await stripe.prices.create({ product: product.id, unit_amount: Math.round(amount * 100), currency: 'usd', }); // Create payment link const paymentLink = await stripe.paymentLinks.create({ line_items: [{ price: price.id, quantity: 1, }], metadata: { user_id: userId, credits: credits.toString(), }, after_completion: { type: 'redirect', redirect: { url: 'https://flow.ruv.net/payment/success', }, }, }); // Store in database await supabase .from('payment_links') .insert({ user_id: userId, stripe_payment_link_id: paymentLink.id, stripe_payment_link_url: paymentLink.url, type: 'deposit', amount: amount, credits_amount: credits, expires_at: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), }); return { success: true, payment_url: paymentLink.url, amount: amount, credits: credits, message: `Payment link created: ${paymentLink.url}`, }; } catch (error) { return { success: false, error: error.message, }; } }, }); // Tool: configure_auto_refill server.addTool({ name: 'configure_auto_refill', description: 'Configure automatic credit refill settings', inputSchema: { type: 'object', properties: { enabled: { type: 'boolean', description: 'Enable or disable auto-refill', }, threshold: { type: 'number', description: 'Credit threshold to trigger refill', minimum: 10, }, amount: { type: 'number', description: 'Amount in USD to refill', minimum: 10, }, user_id: { type: 'string', description: 'User ID (optional)', }, }, required: ['enabled'], }, handler: async (params, context) => { try { const userId = params.user_id || context.user?.id; // Check if user has payment method const { data: profile } = await supabase .from('profiles') .select('stripe_payment_method_id') .eq('id', userId) .single(); if (params.enabled && !profile?.stripe_payment_method_id) { return { success: false, error: 'No payment method on file. Complete a payment first.', }; } // Update settings const updates = { auto_refill_enabled: params.enabled, updated_at: new Date().toISOString(), }; if (params.threshold !== undefined) { updates.auto_refill_threshold = params.threshold; } if (params.amount !== undefined) { updates.auto_refill_amount = params.amount; } const { error } = await supabase .from('profiles') .update(updates) .eq('id', userId); if (error) { throw error; } return { success: true, enabled: params.enabled, threshold: params.threshold, amount: params.amount, message: `Auto-refill ${params.enabled ? 'enabled' : 'disabled'}`, }; } catch (error) { return { success: false, error: error.message, }; } }, }); // Tool: get_payment_history server.addTool({ name: 'get_payment_history', description: 'Get recent payment and transaction history', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Number of transactions to return', minimum: 1, maximum: 100, default: 10, }, user_id: { type: 'string', description: 'User ID (optional)', }, }, }, handler: async (params, context) => { try { const userId = params.user_id || context.user?.id; const limit = params.limit || 10; const { data: transactions, error } = await supabase .from('stripe_transactions') .select('*') .eq('user_id', userId) .order('created_at', { ascending: false }) .limit(limit); if (error) { throw error; } return { success: true, transactions: transactions || [], count: transactions?.length || 0, message: `Found ${transactions?.length || 0} transactions`, }; } catch (error) { return { success: false, error: error.message, }; } }, }); // Tool: create_subscription server.addTool({ name: 'create_subscription', description: 'Create a monthly subscription for automatic credits', inputSchema: { type: 'object', properties: { plan: { type: 'string', enum: ['starter', 'pro', 'enterprise'], description: 'Subscription plan', }, user_id: { type: 'string', description: 'User ID (optional)', }, }, required: ['plan'], }, handler: async (params, context) => { try { const userId = params.user_id || context.user?.id; const plans = { starter: { price: 29, credits: 1000, priceId: 'price_starter' }, pro: { price: 99, credits: 5000, priceId: 'price_pro' }, enterprise: { price: 299, credits: 20000, priceId: 'price_enterprise' }, }; const plan = plans[params.plan]; // Get user profile const { data: profile } = await supabase .from('profiles') .select('stripe_customer_id') .eq('id', userId) .single(); if (!profile?.stripe_customer_id) { return { success: false, error: 'Complete a payment first to set up subscription', }; } // Create subscription const subscription = await stripe.subscriptions.create({ customer: profile.stripe_customer_id, items: [{ price: plan.priceId }], payment_behavior: 'default_incomplete', expand: ['latest_invoice.payment_intent'], metadata: { user_id: userId, credits_per_month: plan.credits.toString(), }, }); return { success: true, subscription_id: subscription.id, plan: params.plan, price: plan.price, credits_per_month: plan.credits, message: `${params.plan} subscription created ($${plan.price}/month for ${plan.credits} credits)`, }; } catch (error) { return { success: false, error: error.message, }; } }, }); // Tool: reduce_credits (Admin only) server.addTool({ name: 'reduce_credits', description: 'Reduce user credits for testing (admin only)', inputSchema: { type: 'object', properties: { email: { type: 'string', description: 'User email address', }, target_balance: { type: 'number', description: 'Target credit balance', minimum: 0, }, }, required: ['email', 'target_balance'], }, handler: async (params, context) => { try { // Check admin permission if (!context.isAdmin) { return { success: false, error: 'Admin permission required', }; } const { error } = await supabase .from('profiles') .update({ credits_balance: params.target_balance, ruv_credits: params.target_balance, updated_at: new Date().toISOString(), }) .eq('email', params.email); if (error) { throw error; } // Check if notifications will trigger const notifications = []; if (params.target_balance < 20) { notifications.push('Low balance notification will trigger'); } if (params.target_balance === 0) { notifications.push('User will be blocked from paid tools'); } return { success: true, email: params.email, new_balance: params.target_balance, notifications: notifications, message: `Credits reduced to ${params.target_balance} for ${params.email}`, }; } catch (error) { return { success: false, error: error.message, }; } }, }); // Log to stderr only to avoid breaking MCP protocol if (process.stderr && process.env.MCP_MODE !== 'stdio') { console.error(chalk.green('✅ Payment tools registered with flow-nexus MCP server')); } } // Export individual tool handlers for testing export const paymentTools = { check_balance: 'check_balance', create_payment_link: 'create_payment_link', configure_auto_refill: 'configure_auto_refill', get_payment_history: 'get_payment_history', create_subscription: 'create_subscription', reduce_credits: 'reduce_credits', };