add_revenue
Record closed deals and revenue data in Google Sheets for tracking business performance and managing sales pipeline through the Revenue Engine MCP server.
Instructions
Add a closed deal
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| clientName | Yes | ||
| contractValue | Yes | ||
| leadId | No | ||
| notes | No | ||
| paymentReceived | No | ||
| projectDescription | No | ||
| serviceType | No | ||
| status | No |
Implementation Reference
- index.js:650-652 (handler)Handler case for the 'add_revenue' tool. Executes by calling the external Google Apps Script API with action 'addRevenue' and passing the tool arguments.case "add_revenue": result = await callAPI("addRevenue", args); break;
- index.js:240-263 (schema)Input schema definition for the 'add_revenue' tool, including properties, types, enums, and required fields.{ name: "add_revenue", description: "Add a closed deal", inputSchema: { type: "object", properties: { clientName: { type: "string" }, leadId: { type: "number" }, serviceType: { type: "string", enum: ["Website", "Automation", "SaaS Consulting", "Combined", "Other"] }, projectDescription: { type: "string" }, contractValue: { type: "number" }, status: { type: "string", enum: ["Proposed", "Accepted", "In Progress", "Delivered", "Paid"] }, paymentReceived: { type: "number" }, notes: { type: "string" }, }, required: ["clientName", "contractValue"], }, },
- index.js:147-615 (registration)Registration of all tools including 'add_revenue' in the ListToolsRequestHandler. This makes the tool discoverable by MCP clients.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: [ { name: "get_dashboard", description: "Get current revenue dashboard with all key metrics", inputSchema: { type: "object", properties: {}, }, }, { name: "get_pipeline", description: "Get all leads in the pipeline", inputSchema: { type: "object", properties: {}, }, }, { name: "get_upcoming_meetings", description: "Get upcoming meetings from Google Calendar (next 7 days)", inputSchema: { type: "object", properties: {}, }, }, { name: "add_lead", description: "Add a new lead to the pipeline", inputSchema: { type: "object", properties: { companyName: { type: "string", description: "Company name" }, contactName: { type: "string", description: "Contact person name" }, contactEmail: { type: "string", description: "Contact email" }, contactPhone: { type: "string", description: "Contact phone" }, industry: { type: "string", description: "Industry/sector" }, source: { type: "string", description: "Lead source", enum: ["Upwork", "LinkedIn", "Cold Email", "Referral", "Website", "Other"] }, estimatedValue: { type: "number", description: "Estimated project value" }, servicesInterestedIn: { type: "string", description: "Services interested in" }, notes: { type: "string", description: "Additional notes" }, }, required: ["companyName"], }, }, { name: "update_lead", description: "Update an existing lead", inputSchema: { type: "object", properties: { leadId: { type: "number", description: "Lead ID to update" }, status: { type: "string", enum: ["New", "Contacted", "Call Booked", "Proposal Sent", "Closed", "Lost"] }, estimatedValue: { type: "number" }, notes: { type: "string" }, nextAction: { type: "string" }, nextActionDate: { type: "string", description: "YYYY-MM-DD" }, }, required: ["leadId"], }, }, { name: "log_outreach", description: "Log an outreach activity", inputSchema: { type: "object", properties: { leadId: { type: "number" }, companyName: { type: "string" }, channel: { type: "string", enum: ["Cold Email", "LinkedIn", "Upwork", "Phone", "Gmail", "Other"] }, templateUsed: { type: "string" }, templateId: { type: "number" }, responseReceived: { type: "string", enum: ["Yes", "No"] }, responseType: { type: "string", enum: ["Interested", "Not Interested", "Question", "Meeting Booked", "No Response"] }, notes: { type: "string" }, }, required: ["companyName", "channel"], }, }, { name: "add_revenue", description: "Add a closed deal", inputSchema: { type: "object", properties: { clientName: { type: "string" }, leadId: { type: "number" }, serviceType: { type: "string", enum: ["Website", "Automation", "SaaS Consulting", "Combined", "Other"] }, projectDescription: { type: "string" }, contractValue: { type: "number" }, status: { type: "string", enum: ["Proposed", "Accepted", "In Progress", "Delivered", "Paid"] }, paymentReceived: { type: "number" }, notes: { type: "string" }, }, required: ["clientName", "contractValue"], }, }, { name: "add_task", description: "Add a new task", inputSchema: { type: "object", properties: { taskDescription: { type: "string" }, priority: { type: "string", enum: ["High", "Medium", "Low"] }, dueDate: { type: "string", description: "YYYY-MM-DD" }, relatedTo: { type: "string" }, estimatedHours: { type: "number" }, notes: { type: "string" }, }, required: ["taskDescription"], }, }, { name: "get_tasks", description: "Get all tasks", inputSchema: { type: "object", properties: {}, }, }, { name: "update_task", description: "Update a task", inputSchema: { type: "object", properties: { taskId: { type: "number" }, status: { type: "string", enum: ["To Do", "In Progress", "Completed", "Blocked"] }, actualHours: { type: "number" }, notes: { type: "string" }, }, required: ["taskId"], }, }, { name: "get_templates", description: "Get message templates with performance metrics", inputSchema: { type: "object", properties: {}, }, }, { name: "log_daily_metrics", description: "Log daily activity metrics", inputSchema: { type: "object", properties: { date: { type: "string", description: "YYYY-MM-DD" }, outreachAttempts: { type: "number" }, responses: { type: "number" }, callsBooked: { type: "number" }, proposalsSent: { type: "number" }, dealsClosed: { type: "number" }, revenueClosed: { type: "number" }, }, }, }, { name: "get_metrics", description: "Get recent daily metrics (last 7 days)", inputSchema: { type: "object", properties: {}, }, }, { name: "search_gmail", description: "Search Gmail inbox. Use Gmail search syntax like 'from:email@example.com' or 'is:unread' or 'subject:proposal'", inputSchema: { type: "object", properties: { query: { type: "string", description: "Gmail search query (default: 'is:unread')" }, maxResults: { type: "number", description: "Max results (default: 25, max: 100)" } } } }, { name: "get_email_content", description: "Get full content of an email thread by ID. Returns complete email body, attachments info, and all messages in the thread.", inputSchema: { type: "object", properties: { threadId: { type: "string", description: "Gmail thread ID (get this from search_gmail results)" } }, required: ["threadId"] } }, { name: "send_email", description: "Send an email via Gmail. ALWAYS get user approval before calling this.", inputSchema: { type: "object", properties: { to: { type: "string", description: "Recipient email address" }, subject: { type: "string", description: "Email subject line" }, body: { type: "string", description: "Email body content" } }, required: ["to", "subject", "body"] } }, { name: "check_new_leads", description: "Check for new leads added in last 24 hours that need welcome emails", inputSchema: { type: "object", properties: {} } }, // MATRIX KNOWLEDGE BASE TOOLS { name: "setup_matrix_sheet", description: "Auto-create Knowledge Matrix sheet with proper structure and headers. Run this once before using other Matrix tools.", inputSchema: { type: "object", properties: {} } }, { name: "write_matrix_entry", description: "Write or append entry to Knowledge Matrix. Topics: Bugs & Fixes, Features Added, Testing Results, Decisions & Direction, Documentation Updates, Next Session Goals", inputSchema: { type: "object", properties: { date: { type: "string", description: "Date in YYYY-MM-DD format (defaults to today)" }, topic: { type: "string", description: "Matrix topic", enum: ["Bugs & Fixes", "Features Added", "Testing Results", "Decisions & Direction", "Documentation Updates", "Next Session Goals"] }, content: { type: "string", description: "Entry content with timestamp (e.g., '3:45pm CST 🐛 Fixed bug in addTask')" } }, required: ["topic", "content"] } }, { name: "read_matrix_snapshot", description: "Read Matrix entries for a date range. Returns all entries for specified topics and dates.", inputSchema: { type: "object", properties: { startDate: { type: "string", description: "Start date YYYY-MM-DD (optional, defaults to beginning)" }, endDate: { type: "string", description: "End date YYYY-MM-DD (optional, defaults to today)" }, topics: { type: "array", items: { type: "string" }, description: "Array of topics to include (optional, defaults to all)" } } } }, { name: "get_matrix_row", description: "Get all topics for a specific date. Returns complete row from Matrix.", inputSchema: { type: "object", properties: { date: { type: "string", description: "Date in YYYY-MM-DD format (defaults to today)" } } } }, { name: "query_matrix", description: "Search Matrix for keyword across topics and dates", inputSchema: { type: "object", properties: { keyword: { type: "string", description: "Search term" }, topics: { type: "array", items: { type: "string" }, description: "Topics to search (optional, defaults to all)" }, limit: { type: "number", description: "Max results (default 50)" } }, required: ["keyword"] } }, { name: "delete_matrix_rows", description: "Delete rows from Knowledge Matrix with confirmation requirement. First call shows preview, second call with confirm=true executes deletion. Cannot delete header rows (1-2).", inputSchema: { type: "object", properties: { startRow: { type: "number", description: "First row to delete (must be >= 3)" }, endRow: { type: "number", description: "Last row to delete (inclusive)" }, confirm: { type: "boolean", description: "Set to true to actually delete (first call without this shows preview)" } }, required: ["startRow", "endRow"] } }, { name: "matrix_daily_summary", description: "Generate formatted summary of Matrix entries for a specific date. Automatically parses timestamps, bug UIDs, time spent, and generates human-readable output.", inputSchema: { type: "object", properties: { date: { type: "string", description: "Date in YYYY-MM-DD format (defaults to today)" }, format: { type: "string", description: "Output format", enum: ["bullet", "prose", "slack"] } } } }, { name: "matrix_time_analysis", description: "Analyze time spent across Matrix entries. Tracks total time by topic, bug UID, or week. Parses time markers like [30m], [2h] from entries.", inputSchema: { type: "object", properties: { startDate: { type: "string", description: "Start date YYYY-MM-DD (optional, defaults to beginning)" }, endDate: { type: "string", description: "End date YYYY-MM-DD (optional, defaults to today)" }, groupBy: { type: "string", description: "How to group the analysis", enum: ["topic", "bug", "week", "day"] } } } }, // FILE SYSTEM TOOLS { name: "read_file", description: "Read contents of a file. Only works in allowed directories: revenue-engine-mcp, apps-script folders", inputSchema: { type: "object", properties: { path: { type: "string", description: "Full file path (e.g., C:\\Users\\Node1\\revenue-engine-mcp\\index.js)" } }, required: ["path"] } }, { name: "edit_file", description: "Surgically edit a file by finding and replacing exact text. 50% more efficient than read+write. Use after read_file to ensure exact match. Errors if text not found or appears multiple times. Creates backup automatically.", inputSchema: { type: "object", properties: { path: { type: "string", description: "Full file path" }, find: { type: "string", description: "Exact text to find (must match exactly including whitespace)" }, replace_with: { type: "string", description: "Text to replace it with" } }, required: ["path", "find", "replace_with"] } }, { name: "write_file", description: "Write or update entire file. Creates backup automatically. Use for complex multi-location edits or new files. Only works in allowed directories.", inputSchema: { type: "object", properties: { path: { type: "string", description: "Full file path" }, content: { type: "string", description: "File content to write" } }, required: ["path", "content"] } }, { name: "run_command", description: "Execute allowed shell commands (clasp, npm, git, dir). For clasp commands, run from apps-script folder.", inputSchema: { type: "object", properties: { command: { type: "string", description: "Command to run (must be in allowed list)" }, workingDirectory: { type: "string", description: "Directory to run command in (optional, defaults to revenue-engine-mcp)" } }, required: ["command"] } } ], }; });
- index.js:74-131 (helper)Shared helper function callAPI used by the 'add_revenue' handler (and others) to proxy requests to the backend Google Apps Script API.async function callAPI(action, data = {}) { debugLog('=== API CALL START ==='); debugLog(`Action: ${action}`); debugLog(`Data: ${JSON.stringify(data)}`); try { // Build form-encoded body for POST const formData = new URLSearchParams(); formData.append('action', action); // Add all data fields to form for (const [key, value] of Object.entries(data)) { if (value !== undefined && value !== null) { formData.append(key, value.toString()); } } const formString = formData.toString(); debugLog(`FormData: ${formString}`); debugLog(`API_URL: ${API_URL}`); // Use POST with proper content type const response = await fetch(API_URL, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: formString }); debugLog(`Response status: ${response.status}`); debugLog(`Response ok: ${response.ok}`); if (!response.ok) { debugLog(`Response not OK: ${response.status} ${response.statusText}`); throw new Error(`API request failed: ${response.status} ${response.statusText}`); } const text = await response.text(); debugLog(`Response text length: ${text.length}`); debugLog(`Response text: ${text}`); if (!text) { debugLog('ERROR: Empty response from API'); throw new Error('Empty response from API'); } const parsed = JSON.parse(text); debugLog(`Parsed successfully: ${JSON.stringify(parsed)}`); debugLog('=== API CALL END ==='); return parsed; } catch (error) { debugLog(`ERROR in callAPI: ${error.message}`); debugLog(`ERROR stack: ${error.stack}`); throw error; } }