Skip to main content
Glama
mcp-server.ts•69.8 kB
#!/usr/bin/env node /** * Office Whisperer - MCP Server v3.0 * 63 Professional Tools for Microsoft Office Suite Automation * Control Excel, Word, PowerPoint, and Outlook through natural language with Claude Desktop */ import { ExcelGenerator } from './generators/excel-generator.js'; import { WordGenerator } from './generators/word-generator.js'; import { PowerPointGenerator } from './generators/powerpoint-generator.js'; import { OutlookGenerator } from './generators/outlook-generator.js'; import type { MCPRequest, MCPResponse, MCPTool } from './types.js'; import * as fs from 'fs/promises'; import * as path from 'path'; class OfficeWhispererServer { private excelGen = new ExcelGenerator(); private wordGen = new WordGenerator(); private pptGen = new PowerPointGenerator(); private outlookGen = new OutlookGenerator(); private tools: MCPTool[] = [ // ========== EXCEL TOOLS (21 tools) ========== { name: 'create_excel', description: 'šŸ“Š Create Excel workbook with sheets, data, formulas, and charts', inputSchema: { type: 'object', properties: { filename: { type: 'string', description: 'Output filename (e.g., "report.xlsx")' }, sheets: { type: 'array', description: 'Array of sheet configurations' }, outputPath: { type: 'string', description: 'Optional output directory' }, }, required: ['filename', 'sheets'], }, }, { name: 'excel_add_pivot_table', description: 'šŸ“ˆ Add pivot table with rows, columns, values, and filters', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, pivotTable: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'pivotTable'], }, }, { name: 'excel_add_chart', description: 'šŸ“‰ Add chart (line/bar/pie/scatter/area) with customization', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, chart: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'chart'], }, }, { name: 'excel_add_formula', description: 'šŸ”¢ Add formulas (VLOOKUP, SUMIF, INDEX/MATCH, IF, etc)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, formulas: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'formulas'], }, }, { name: 'excel_conditional_formatting', description: 'šŸŽØ Apply conditional formatting (color scales, data bars, icon sets)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, range: { type: 'string' }, rules: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'range', 'rules'], }, }, { name: 'excel_data_validation', description: 'āœ… Add dropdown lists and validation rules', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, range: { type: 'string' }, validation: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'range', 'validation'], }, }, { name: 'excel_freeze_panes', description: 'ā„ļø Freeze rows/columns for scrolling', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, row: { type: 'number' }, column: { type: 'number' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName'], }, }, { name: 'excel_filter_sort', description: 'šŸ” Apply AutoFilter and sorting', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, range: { type: 'string' }, sortBy: { type: 'array' }, autoFilter: { type: 'boolean' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName'], }, }, { name: 'excel_format_cells', description: '✨ Format cells (fonts, colors, borders, alignment, number formats)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, range: { type: 'string' }, style: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'range', 'style'], }, }, { name: 'excel_named_range', description: 'šŸ·ļø Create and manage named ranges', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, name: { type: 'string' }, range: { type: 'string' }, sheetName: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['filename', 'name', 'range'], }, }, { name: 'excel_protect_sheet', description: 'šŸ”’ Protect worksheets with passwords', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, password: { type: 'string' }, options: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName'], }, }, { name: 'excel_merge_workbooks', description: 'šŸ”— Merge multiple Excel files', inputSchema: { type: 'object', properties: { files: { type: 'array' }, outputFilename: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['files', 'outputFilename'], }, }, { name: 'excel_find_replace', description: 'šŸ”Ž Find and replace values/formulas', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, find: { type: 'string' }, replace: { type: 'string' }, matchCase: { type: 'boolean' }, matchEntireCell: { type: 'boolean' }, searchFormulas: { type: 'boolean' }, outputPath: { type: 'string' }, }, required: ['filename', 'find', 'replace'], }, }, { name: 'excel_to_json', description: 'šŸ“‹ Export Excel to JSON format', inputSchema: { type: 'object', properties: { excelPath: { type: 'string' }, sheetName: { type: 'string' }, outputPath: { type: 'string' }, header: { type: 'boolean' }, }, required: ['excelPath'], }, }, { name: 'excel_to_csv', description: 'šŸ“„ Convert Excel to CSV format', inputSchema: { type: 'object', properties: { excelPath: { type: 'string' }, sheetName: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['excelPath'], }, }, { name: 'excel_add_sparklines', description: '✨ Add sparklines (mini charts in cells)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, dataRange: { type: 'string' }, location: { type: 'string' }, type: { type: 'string', enum: ['line', 'column', 'winLoss'] }, options: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'dataRange', 'location', 'type'], }, }, { name: 'excel_array_formulas', description: 'šŸ”¢ Add dynamic array formulas (UNIQUE, SORT, FILTER)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, formulas: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'formulas'], }, }, { name: 'excel_add_subtotals', description: 'šŸ“Š Add subtotals with grouping', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, range: { type: 'string' }, groupBy: { type: 'number' }, summaryFunction: { type: 'string', enum: ['SUM', 'COUNT', 'AVERAGE', 'MAX', 'MIN'] }, summaryColumns: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'range', 'groupBy', 'summaryFunction', 'summaryColumns'], }, }, { name: 'excel_add_hyperlinks', description: 'šŸ”— Add hyperlinks to cells (URLs or internal links)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, links: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'links'], }, }, { name: 'excel_advanced_charts', description: 'šŸ“ˆ Create advanced charts (waterfall, funnel, treemap, sunburst)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, chart: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'chart'], }, }, { name: 'excel_add_slicers', description: 'šŸŽ›ļø Add slicers for tables/pivot tables', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sheetName: { type: 'string' }, tableName: { type: 'string' }, slicers: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'sheetName', 'tableName', 'slicers'], }, }, // ========== WORD TOOLS (16 tools) ========== { name: 'create_word', description: 'šŸ“ Create Word document with paragraphs, tables, images, and formatting', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, title: { type: 'string' }, sections: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'sections'], }, }, { name: 'word_add_toc', description: 'šŸ“‘ Add table of contents', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, outputPath: { type: 'string' }, title: { type: 'string' }, hyperlinks: { type: 'boolean' }, levels: { type: 'number' }, }, required: ['filename'], }, }, { name: 'word_mail_merge', description: 'āœ‰ļø Mail merge with data source', inputSchema: { type: 'object', properties: { templatePath: { type: 'string' }, dataSource: { type: 'array' }, outputPath: { type: 'string' }, outputFilename: { type: 'string' }, }, required: ['templatePath', 'dataSource'], }, }, { name: 'word_find_replace', description: 'šŸ” Find and replace text with formatting', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, find: { type: 'string' }, replace: { type: 'string' }, matchCase: { type: 'boolean' }, matchWholeWord: { type: 'boolean' }, formatting: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'find', 'replace'], }, }, { name: 'word_add_comment', description: 'šŸ’¬ Add comments and track changes', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, text: { type: 'string' }, comment: { type: 'string' }, author: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['filename', 'text', 'comment'], }, }, { name: 'word_format_styles', description: 'šŸŽØ Apply and customize styles/themes', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, styles: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'styles'], }, }, { name: 'word_insert_image', description: 'šŸ–¼ļø Insert and position images with wrapping', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, imagePath: { type: 'string' }, position: { type: 'object' }, size: { type: 'object' }, wrapping: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['filename', 'imagePath'], }, }, { name: 'word_add_header_footer', description: 'šŸ“„ Customize headers/footers per section', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, type: { type: 'string', enum: ['header', 'footer'] }, content: { type: 'array' }, sectionType: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['filename', 'type', 'content'], }, }, { name: 'word_compare_documents', description: 'šŸ”„ Compare two documents and show differences', inputSchema: { type: 'object', properties: { originalPath: { type: 'string' }, revisedPath: { type: 'string' }, outputPath: { type: 'string' }, author: { type: 'string' }, }, required: ['originalPath', 'revisedPath'], }, }, { name: 'word_to_pdf', description: 'šŸ“‘ Export Word document to PDF', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['filename'], }, }, { name: 'word_track_changes', description: 'āœļø Enable/disable track changes', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, enable: { type: 'boolean' }, author: { type: 'string' }, showMarkup: { type: 'boolean' }, trackFormatting: { type: 'boolean' }, trackMoves: { type: 'boolean' }, outputPath: { type: 'string' }, }, required: ['filename', 'enable'], }, }, { name: 'word_add_footnotes', description: 'šŸ“Œ Add footnotes and endnotes', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, footnotes: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'footnotes'], }, }, { name: 'word_add_bookmarks', description: 'šŸ”– Add bookmarks to text', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, bookmarks: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'bookmarks'], }, }, { name: 'word_add_section_breaks', description: 'šŸ“„ Add section breaks (next page, continuous, even/odd page)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, breaks: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'breaks'], }, }, { name: 'word_add_text_boxes', description: 'šŸ“¦ Add text boxes with positioning', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, textBoxes: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'textBoxes'], }, }, { name: 'word_add_cross_references', description: 'šŸ”— Add cross-references to bookmarks', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, references: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'references'], }, }, // ========== POWERPOINT TOOLS (13 tools) ========== { name: 'create_powerpoint', description: 'šŸŽ¬ Create PowerPoint presentation with slides, text, images, and charts', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, title: { type: 'string' }, theme: { type: 'string', enum: ['default', 'light', 'dark', 'colorful'] }, slides: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'slides'], }, }, { name: 'ppt_add_transition', description: '✨ Add slide transitions (fade, push, wipe, etc)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, slideNumber: { type: 'number' }, transition: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'transition'], }, }, { name: 'ppt_add_animation', description: 'šŸŽ­ Add animations to objects (entrance, emphasis, exit)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, slideNumber: { type: 'number' }, objectId: { type: 'string' }, animation: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'slideNumber', 'animation'], }, }, { name: 'ppt_add_notes', description: 'šŸ“ Add/edit speaker notes', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, slideNumber: { type: 'number' }, notes: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['filename', 'slideNumber', 'notes'], }, }, { name: 'ppt_duplicate_slide', description: 'šŸ“‹ Duplicate slides', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, slideNumber: { type: 'number' }, position: { type: 'number' }, outputPath: { type: 'string' }, }, required: ['filename', 'slideNumber'], }, }, { name: 'ppt_reorder_slides', description: 'šŸ”€ Reorder slide sequence', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, slideOrder: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'slideOrder'], }, }, { name: 'ppt_export_pdf', description: 'šŸ“‘ Export presentation to PDF', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['filename'], }, }, { name: 'ppt_add_media', description: 'šŸŽ„ Embed video/audio', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, slideNumber: { type: 'number' }, mediaPath: { type: 'string' }, mediaType: { type: 'string', enum: ['video', 'audio'] }, position: { type: 'object' }, size: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'slideNumber', 'mediaPath', 'mediaType'], }, }, { name: 'ppt_define_master_slide', description: 'šŸŽØ Define custom master slide templates', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, masterSlide: { type: 'object' }, outputPath: { type: 'string' }, }, required: ['filename', 'masterSlide'], }, }, { name: 'ppt_add_hyperlinks', description: 'šŸ”— Add hyperlinks to text/objects (URLs or slide links)', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, slideNumber: { type: 'number' }, links: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'slideNumber', 'links'], }, }, { name: 'ppt_add_sections', description: 'šŸ“ Organize slides into sections', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, sections: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'sections'], }, }, { name: 'ppt_morph_transition', description: '✨ Add morph transition between slides', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, fromSlide: { type: 'number' }, toSlide: { type: 'number' }, duration: { type: 'number' }, outputPath: { type: 'string' }, }, required: ['filename', 'fromSlide', 'toSlide'], }, }, { name: 'ppt_add_action_buttons', description: 'šŸ”˜ Add interactive action buttons', inputSchema: { type: 'object', properties: { filename: { type: 'string' }, slideNumber: { type: 'number' }, buttons: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['filename', 'slideNumber', 'buttons'], }, }, // ========== OUTLOOK TOOLS (13 tools) ========== { name: 'outlook_send_email', description: 'šŸ“§ Send emails with attachments', inputSchema: { type: 'object', properties: { to: { type: 'string' }, subject: { type: 'string' }, body: { type: 'string' }, cc: { type: 'string' }, bcc: { type: 'string' }, attachments: { type: 'array' }, html: { type: 'boolean' }, priority: { type: 'string', enum: ['high', 'normal', 'low'] }, smtpConfig: { type: 'object' }, }, required: ['to', 'subject', 'body'], }, }, { name: 'outlook_create_meeting', description: 'šŸ“… Create calendar events with attendees', inputSchema: { type: 'object', properties: { subject: { type: 'string' }, startTime: { type: 'string' }, endTime: { type: 'string' }, location: { type: 'string' }, attendees: { type: 'array' }, description: { type: 'string' }, reminder: { type: 'number' }, outputPath: { type: 'string' }, }, required: ['subject', 'startTime', 'endTime'], }, }, { name: 'outlook_add_contact', description: 'šŸ‘¤ Add contact to address book', inputSchema: { type: 'object', properties: { firstName: { type: 'string' }, lastName: { type: 'string' }, email: { type: 'string' }, phone: { type: 'string' }, company: { type: 'string' }, jobTitle: { type: 'string' }, address: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['firstName', 'lastName'], }, }, { name: 'outlook_create_task', description: 'āœ… Create Outlook task', inputSchema: { type: 'object', properties: { subject: { type: 'string' }, dueDate: { type: 'string' }, priority: { type: 'string', enum: ['high', 'normal', 'low'] }, status: { type: 'string' }, category: { type: 'string' }, reminder: { type: 'string' }, notes: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['subject'], }, }, { name: 'outlook_set_rule', description: 'āš™ļø Create inbox rule', inputSchema: { type: 'object', properties: { name: { type: 'string' }, conditions: { type: 'array' }, actions: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['name', 'conditions', 'actions'], }, }, { name: 'outlook_read_emails', description: 'šŸ“¬ Read emails from IMAP server', inputSchema: { type: 'object', properties: { folder: { type: 'string' }, limit: { type: 'number' }, unreadOnly: { type: 'boolean' }, since: { type: 'string' }, imapConfig: { type: 'object' }, }, }, }, { name: 'outlook_search_emails', description: 'šŸ” Search emails by query', inputSchema: { type: 'object', properties: { query: { type: 'string' }, searchIn: { type: 'array' }, folder: { type: 'string' }, limit: { type: 'number' }, since: { type: 'string' }, imapConfig: { type: 'object' }, }, required: ['query'], }, }, { name: 'outlook_recurring_meeting', description: 'šŸ”„ Create recurring calendar meetings', inputSchema: { type: 'object', properties: { subject: { type: 'string' }, startTime: { type: 'string' }, endTime: { type: 'string' }, recurrence: { type: 'object' }, location: { type: 'string' }, attendees: { type: 'array' }, description: { type: 'string' }, outputPath: { type: 'string' }, }, required: ['subject', 'startTime', 'endTime', 'recurrence'], }, }, { name: 'outlook_save_template', description: 'šŸ“§ Save email template with placeholders', inputSchema: { type: 'object', properties: { name: { type: 'string' }, subject: { type: 'string' }, body: { type: 'string' }, html: { type: 'boolean' }, placeholders: { type: 'array' }, outputPath: { type: 'string' }, }, required: ['name', 'subject', 'body'], }, }, { name: 'outlook_mark_read', description: 'āœ‰ļø Mark emails as read/unread', inputSchema: { type: 'object', properties: { messageIds: { type: 'array' }, markAsRead: { type: 'boolean' }, imapConfig: { type: 'object' }, }, required: ['messageIds', 'markAsRead'], }, }, { name: 'outlook_archive_email', description: 'šŸ“¦ Archive emails to folder', inputSchema: { type: 'object', properties: { messageIds: { type: 'array' }, archiveFolder: { type: 'string' }, imapConfig: { type: 'object' }, }, required: ['messageIds'], }, }, { name: 'outlook_calendar_view', description: 'šŸ“… Get calendar view for date range', inputSchema: { type: 'object', properties: { startDate: { type: 'string' }, endDate: { type: 'string' }, viewType: { type: 'string', enum: ['day', 'week', 'month', 'agenda'] }, outputFormat: { type: 'string', enum: ['ics', 'json'] }, outputPath: { type: 'string' }, }, required: ['startDate', 'endDate', 'viewType'], }, }, { name: 'outlook_search_contacts', description: 'šŸ‘„ Search contacts database', inputSchema: { type: 'object', properties: { query: { type: 'string' }, searchIn: { type: 'array' }, outputFormat: { type: 'string', enum: ['vcf', 'json'] }, outputPath: { type: 'string' }, }, required: ['query'], }, }, ]; async start(): Promise<void> { process.stdin.setEncoding('utf-8'); let buffer = ''; process.stdin.on('data', async (chunk) => { buffer += chunk; const lines = buffer.split('\n'); buffer = lines.pop() || ''; for (const line of lines) { if (line.trim()) { try { const request: MCPRequest = JSON.parse(line); const response = await this.handleRequest(request); if (response) { console.log(JSON.stringify(response)); } } catch (error) { console.error('Error processing request:', error); } } } }); process.stdin.on('end', () => { process.exit(0); }); } private async handleRequest(request: MCPRequest): Promise<MCPResponse | null> { const { id, method, params } = request; if (id === undefined) { if (method === 'notifications/initialized') { return null; } return null; } try { switch (method) { case 'initialize': return this.initialize(id); case 'tools/list': return { jsonrpc: '2.0', id, result: { tools: this.tools }, }; case 'tools/call': return await this.callTool(id, params); default: return { jsonrpc: '2.0', id, error: { code: -32601, message: `Method not found: ${method}`, }, }; } } catch (error) { return { jsonrpc: '2.0', id, error: { code: -32603, message: error instanceof Error ? error.message : 'Internal error', }, }; } } private initialize(id: string | number): MCPResponse { return { jsonrpc: '2.0', id, result: { protocolVersion: '2025-06-18', capabilities: { tools: {}, }, serverInfo: { name: 'office-whisperer', version: '3.0.0', }, }, }; } private async callTool(id: string | number, params: any): Promise<MCPResponse> { const { name, arguments: args } = params; let result: any; try { // Excel Tools if (name === 'create_excel') { result = await this.handleCreateExcel(args); } else if (name === 'excel_add_pivot_table') { result = await this.handleExcelAddPivotTable(args); } else if (name === 'excel_add_chart') { result = await this.handleExcelAddChart(args); } else if (name === 'excel_add_formula') { result = await this.handleExcelAddFormula(args); } else if (name === 'excel_conditional_formatting') { result = await this.handleExcelConditionalFormatting(args); } else if (name === 'excel_data_validation') { result = await this.handleExcelDataValidation(args); } else if (name === 'excel_freeze_panes') { result = await this.handleExcelFreezePanes(args); } else if (name === 'excel_filter_sort') { result = await this.handleExcelFilterSort(args); } else if (name === 'excel_format_cells') { result = await this.handleExcelFormatCells(args); } else if (name === 'excel_named_range') { result = await this.handleExcelNamedRange(args); } else if (name === 'excel_protect_sheet') { result = await this.handleExcelProtectSheet(args); } else if (name === 'excel_merge_workbooks') { result = await this.handleExcelMergeWorkbooks(args); } else if (name === 'excel_find_replace') { result = await this.handleExcelFindReplace(args); } else if (name === 'excel_to_json') { result = await this.handleExcelToJSON(args); } else if (name === 'excel_to_csv') { result = await this.handleExcelToCSV(args); } else if (name === 'excel_add_sparklines') { result = await this.handleExcelAddSparklines(args); } else if (name === 'excel_array_formulas') { result = await this.handleExcelArrayFormulas(args); } else if (name === 'excel_add_subtotals') { result = await this.handleExcelAddSubtotals(args); } else if (name === 'excel_add_hyperlinks') { result = await this.handleExcelAddHyperlinks(args); } else if (name === 'excel_advanced_charts') { result = await this.handleExcelAdvancedCharts(args); } else if (name === 'excel_add_slicers') { result = await this.handleExcelAddSlicers(args); } // Word Tools else if (name === 'create_word') { result = await this.handleCreateWord(args); } else if (name === 'word_add_toc') { result = await this.handleWordAddTOC(args); } else if (name === 'word_mail_merge') { result = await this.handleWordMailMerge(args); } else if (name === 'word_find_replace') { result = await this.handleWordFindReplace(args); } else if (name === 'word_add_comment') { result = await this.handleWordAddComment(args); } else if (name === 'word_format_styles') { result = await this.handleWordFormatStyles(args); } else if (name === 'word_insert_image') { result = await this.handleWordInsertImage(args); } else if (name === 'word_add_header_footer') { result = await this.handleWordAddHeaderFooter(args); } else if (name === 'word_compare_documents') { result = await this.handleWordCompareDocuments(args); } else if (name === 'word_to_pdf') { result = await this.handleWordToPDF(args); } else if (name === 'word_track_changes') { result = await this.handleWordTrackChanges(args); } else if (name === 'word_add_footnotes') { result = await this.handleWordAddFootnotes(args); } else if (name === 'word_add_bookmarks') { result = await this.handleWordAddBookmarks(args); } else if (name === 'word_add_section_breaks') { result = await this.handleWordAddSectionBreaks(args); } else if (name === 'word_add_text_boxes') { result = await this.handleWordAddTextBoxes(args); } else if (name === 'word_add_cross_references') { result = await this.handleWordAddCrossReferences(args); } // PowerPoint Tools else if (name === 'create_powerpoint') { result = await this.handleCreatePowerPoint(args); } else if (name === 'ppt_add_transition') { result = await this.handlePPTAddTransition(args); } else if (name === 'ppt_add_animation') { result = await this.handlePPTAddAnimation(args); } else if (name === 'ppt_add_notes') { result = await this.handlePPTAddNotes(args); } else if (name === 'ppt_duplicate_slide') { result = await this.handlePPTDuplicateSlide(args); } else if (name === 'ppt_reorder_slides') { result = await this.handlePPTReorderSlides(args); } else if (name === 'ppt_export_pdf') { result = await this.handlePPTExportPDF(args); } else if (name === 'ppt_add_media') { result = await this.handlePPTAddMedia(args); } else if (name === 'ppt_define_master_slide') { result = await this.handlePPTDefineMasterSlide(args); } else if (name === 'ppt_add_hyperlinks') { result = await this.handlePPTAddHyperlinks(args); } else if (name === 'ppt_add_sections') { result = await this.handlePPTAddSections(args); } else if (name === 'ppt_morph_transition') { result = await this.handlePPTMorphTransition(args); } else if (name === 'ppt_add_action_buttons') { result = await this.handlePPTAddActionButtons(args); } // Outlook Tools else if (name === 'outlook_send_email') { result = await this.handleOutlookSendEmail(args); } else if (name === 'outlook_create_meeting') { result = await this.handleOutlookCreateMeeting(args); } else if (name === 'outlook_add_contact') { result = await this.handleOutlookAddContact(args); } else if (name === 'outlook_create_task') { result = await this.handleOutlookCreateTask(args); } else if (name === 'outlook_set_rule') { result = await this.handleOutlookSetRule(args); } else if (name === 'outlook_read_emails') { result = await this.handleOutlookReadEmails(args); } else if (name === 'outlook_search_emails') { result = await this.handleOutlookSearchEmails(args); } else if (name === 'outlook_recurring_meeting') { result = await this.handleOutlookRecurringMeeting(args); } else if (name === 'outlook_save_template') { result = await this.handleOutlookSaveTemplate(args); } else if (name === 'outlook_mark_read') { result = await this.handleOutlookMarkRead(args); } else if (name === 'outlook_archive_email') { result = await this.handleOutlookArchiveEmail(args); } else if (name === 'outlook_calendar_view') { result = await this.handleOutlookCalendarView(args); } else if (name === 'outlook_search_contacts') { result = await this.handleOutlookSearchContacts(args); } else { throw new Error(`Unknown tool: ${name}`); } } catch (error) { throw error; } return { jsonrpc: '2.0', id, result: { content: [ { type: 'text', text: result, }, ], }, }; } // ========== EXCEL HANDLERS ========== private async handleCreateExcel(args: any): Promise<string> { const buffer = await this.excelGen.createWorkbook({ filename: args.filename, sheets: args.sheets, }); const outputPath = args.outputPath || process.cwd(); const fullPath = path.join(outputPath, args.filename); await fs.writeFile(fullPath, buffer); return `āœ… **Excel workbook created!**\n\nšŸ“Š **File:** ${fullPath}\nšŸ“ **Sheets:** ${args.sheets.length}\nšŸ’¾ **Size:** ${(buffer.length / 1024).toFixed(2)} KB`; } private async handleExcelAddPivotTable(args: any): Promise<string> { const buffer = await this.excelGen.addPivotTable(args.filename, args.sheetName, args.pivotTable); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Pivot table added!**\n\nšŸ“ˆ **Name:** ${args.pivotTable.name}\nšŸ“Š **File:** ${fullPath}`; } private async handleExcelAddChart(args: any): Promise<string> { const buffer = await this.excelGen.addChart(args.filename, args.sheetName, args.chart); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Chart added!**\n\nšŸ“‰ **Type:** ${args.chart.type}\nšŸ“Š **Title:** ${args.chart.title}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelAddFormula(args: any): Promise<string> { const buffer = await this.excelGen.addFormulas(args.filename, args.sheetName, args.formulas); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Formulas added!**\n\nšŸ”¢ **Count:** ${args.formulas.length}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelConditionalFormatting(args: any): Promise<string> { const buffer = await this.excelGen.addConditionalFormatting(args.filename, args.sheetName, args.range, args.rules); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Conditional formatting applied!**\n\nšŸŽØ **Range:** ${args.range}\nšŸ“Š **Rules:** ${args.rules.length}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelDataValidation(args: any): Promise<string> { const buffer = await this.excelGen.addDataValidation(args.filename, args.sheetName, args.range, args.validation); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Data validation added!**\n\nāœ… **Type:** ${args.validation.type}\nšŸ“ **Range:** ${args.range}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelFreezePanes(args: any): Promise<string> { const buffer = await this.excelGen.freezePanes(args.filename, args.sheetName, args.row, args.column); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Panes frozen!**\n\nā„ļø **Row:** ${args.row || 0}\nā„ļø **Column:** ${args.column || 0}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelFilterSort(args: any): Promise<string> { const buffer = await this.excelGen.filterSort(args.filename, args.sheetName, args.range, args.sortBy, args.autoFilter); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Filter/Sort applied!**\n\nšŸ” **AutoFilter:** ${args.autoFilter ? 'Yes' : 'No'}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelFormatCells(args: any): Promise<string> { const buffer = await this.excelGen.formatCells(args.filename, args.sheetName, args.range, args.style); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Cells formatted!**\n\n✨ **Range:** ${args.range}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelNamedRange(args: any): Promise<string> { const buffer = await this.excelGen.addNamedRange(args.filename, args.name, args.range, args.sheetName); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Named range created!**\n\nšŸ·ļø **Name:** ${args.name}\nšŸ“ **Range:** ${args.range}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelProtectSheet(args: any): Promise<string> { const buffer = await this.excelGen.protectSheet(args.filename, args.sheetName, args.password, args.options); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Sheet protected!**\n\nšŸ”’ **Sheet:** ${args.sheetName}\n${args.password ? 'šŸ”‘ **Password:** Set' : 'šŸ”“ **Password:** None'}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelMergeWorkbooks(args: any): Promise<string> { const buffer = await this.excelGen.mergeWorkbooks(args.files, args.outputFilename); const outputPath = args.outputPath || process.cwd(); const fullPath = path.join(outputPath, args.outputFilename); await fs.writeFile(fullPath, buffer); return `āœ… **Workbooks merged!**\n\nšŸ”— **Source files:** ${args.files.length}\nšŸ“ **Output:** ${fullPath}`; } private async handleExcelFindReplace(args: any): Promise<string> { const buffer = await this.excelGen.findReplace( args.filename, args.find, args.replace, args.sheetName, args.matchCase, args.matchEntireCell, args.searchFormulas ); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Find & Replace complete!**\n\nšŸ”Ž **Find:** "${args.find}"\nšŸ”„ **Replace:** "${args.replace}"\nšŸ“ **File:** ${fullPath}`; } private async handleExcelToJSON(args: any): Promise<string> { const json = await this.excelGen.convertToJSON(args.excelPath, args.sheetName, args.header); const outputPath = args.outputPath || args.excelPath.replace(/\.xlsx?$/i, '.json'); await fs.writeFile(outputPath, json, 'utf-8'); return `āœ… **Converted to JSON!**\n\nšŸ“Š **Source:** ${args.excelPath}\nšŸ“‹ **Output:** ${outputPath}\nšŸ’¾ **Size:** ${(json.length / 1024).toFixed(2)} KB`; } private async handleExcelToCSV(args: any): Promise<string> { const csv = await this.excelGen.convertToCSV(args.excelPath, args.sheetName); const outputPath = args.outputPath || args.excelPath.replace(/\.xlsx?$/i, '.csv'); await fs.writeFile(outputPath, csv, 'utf-8'); return `āœ… **Converted to CSV!**\n\nšŸ“Š **Source:** ${args.excelPath}\nšŸ“ **Output:** ${outputPath}\nšŸ’¾ **Size:** ${(csv.length / 1024).toFixed(2)} KB`; } // ========== WORD HANDLERS ========== private async handleCreateWord(args: any): Promise<string> { const buffer = await this.wordGen.createDocument({ filename: args.filename, sections: args.sections, }); const outputPath = args.outputPath || process.cwd(); const fullPath = path.join(outputPath, args.filename); await fs.writeFile(fullPath, buffer); return `āœ… **Word document created!**\n\nšŸ“„ **File:** ${fullPath}\nšŸ“‘ **Sections:** ${args.sections.length}\nšŸ’¾ **Size:** ${(buffer.length / 1024).toFixed(2)} KB`; } private async handleWordAddTOC(args: any): Promise<string> { const buffer = await this.wordGen.addTableOfContents(args.filename, args.title, args.hyperlinks, args.levels); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Table of Contents added!**\n\nšŸ“‘ **Title:** ${args.title || 'Table of Contents'}\nšŸ“ **File:** ${fullPath}`; } private async handleWordMailMerge(args: any): Promise<string> { const buffers = await this.wordGen.mailMerge(args.templatePath, args.dataSource, args.outputFilename); const outputPath = args.outputPath || process.cwd(); let savedFiles = 0; for (let i = 0; i < buffers.length; i++) { const filename = args.outputFilename ? `${args.outputFilename}_${i + 1}.docx` : `merged_${i + 1}.docx`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, buffers[i]); savedFiles++; } return `āœ… **Mail merge complete!**\n\nāœ‰ļø **Documents created:** ${savedFiles}\nšŸ“ **Output:** ${outputPath}`; } private async handleWordFindReplace(args: any): Promise<string> { const buffer = await this.wordGen.findReplace( args.filename, args.find, args.replace, args.matchCase, args.matchWholeWord, args.formatting ); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Find & Replace complete!**\n\nšŸ” **Find:** "${args.find}"\nšŸ”„ **Replace:** "${args.replace}"\nšŸ“ **File:** ${fullPath}`; } private async handleWordAddComment(args: any): Promise<string> { const buffer = await this.wordGen.addComment(args.filename, args.text, args.comment, args.author); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Comment added!**\n\nšŸ’¬ **Author:** ${args.author || 'Office Whisperer'}\nšŸ“ **File:** ${fullPath}`; } private async handleWordFormatStyles(args: any): Promise<string> { const buffer = await this.wordGen.formatStyles(args.filename, args.styles); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Styles applied!**\n\nšŸŽØ **Custom styles added**\nšŸ“ **File:** ${fullPath}`; } private async handleWordInsertImage(args: any): Promise<string> { const buffer = await this.wordGen.insertImage( args.filename, args.imagePath, args.position, args.size, args.wrapping ); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Image inserted!**\n\nšŸ–¼ļø **Source:** ${args.imagePath}\nšŸ“ **File:** ${fullPath}`; } private async handleWordAddHeaderFooter(args: any): Promise<string> { const buffer = await this.wordGen.addHeaderFooter( args.filename, args.type, args.content, args.sectionType ); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **${args.type.charAt(0).toUpperCase() + args.type.slice(1)} added!**\n\nšŸ“„ **Type:** ${args.type}\nšŸ“ **File:** ${fullPath}`; } private async handleWordCompareDocuments(args: any): Promise<string> { const buffer = await this.wordGen.compareDocuments(args.originalPath, args.revisedPath, args.author); const outputPath = args.outputPath || path.dirname(args.originalPath); const fullPath = path.join(outputPath, 'comparison.docx'); await fs.writeFile(fullPath, buffer); return `āœ… **Documents compared!**\n\nšŸ”„ **Original:** ${args.originalPath}\nšŸ”„ **Revised:** ${args.revisedPath}\nšŸ“ **Report:** ${fullPath}`; } private async handleWordToPDF(args: any): Promise<string> { const buffer = await this.wordGen.convertToPDF(args.filename); const outputPath = args.outputPath || path.dirname(args.filename); const pdfPath = path.join(outputPath, path.basename(args.filename).replace(/\.docx?$/i, '.pdf')); await fs.writeFile(pdfPath, buffer); return `āœ… **PDF conversion info!**\n\nšŸ“‘ **Source:** ${args.filename}\nšŸ“„ **Output:** ${pdfPath}\n\nNote: Actual PDF conversion requires LibreOffice or similar tools.`; } // ========== POWERPOINT HANDLERS ========== private async handleCreatePowerPoint(args: any): Promise<string> { const buffer = await this.pptGen.createPresentation({ filename: args.filename, title: args.title, theme: args.theme, slides: args.slides, }); const outputPath = args.outputPath || process.cwd(); const fullPath = path.join(outputPath, args.filename); await fs.writeFile(fullPath, buffer); return `āœ… **PowerPoint created!**\n\nšŸŽ¬ **File:** ${fullPath}\nšŸŽØ **Theme:** ${args.theme || 'default'}\nšŸ“Š **Slides:** ${args.slides.length}\nšŸ’¾ **Size:** ${(buffer.length / 1024).toFixed(2)} KB`; } private async handlePPTAddTransition(args: any): Promise<string> { const buffer = await this.pptGen.addTransition(args.filename, args.transition, args.slideNumber); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Transition added!**\n\n✨ **Type:** ${args.transition.type}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTAddAnimation(args: any): Promise<string> { const buffer = await this.pptGen.addAnimation(args.filename, args.slideNumber, args.animation, args.objectId); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Animation added!**\n\nšŸŽ­ **Effect:** ${args.animation.effect}\nšŸ“Š **Slide:** ${args.slideNumber}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTAddNotes(args: any): Promise<string> { const buffer = await this.pptGen.addNotes(args.filename, args.slideNumber, args.notes); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Speaker notes added!**\n\nšŸ“ **Slide:** ${args.slideNumber}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTDuplicateSlide(args: any): Promise<string> { const buffer = await this.pptGen.duplicateSlide(args.filename, args.slideNumber, args.position); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Slide duplicated!**\n\nšŸ“‹ **Source:** Slide ${args.slideNumber}\nšŸ“ **Position:** ${args.position || 'end'}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTReorderSlides(args: any): Promise<string> { const buffer = await this.pptGen.reorderSlides(args.filename, args.slideOrder); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Slides reordered!**\n\nšŸ”€ **New order:** ${args.slideOrder.join(', ')}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTExportPDF(args: any): Promise<string> { const buffer = await this.pptGen.exportPDF(args.filename); const outputPath = args.outputPath || path.dirname(args.filename); const pdfPath = path.join(outputPath, path.basename(args.filename).replace(/\.pptx?$/i, '.pdf')); await fs.writeFile(pdfPath, buffer); return `āœ… **PDF export info!**\n\nšŸ“‘ **Source:** ${args.filename}\nšŸ“„ **Output:** ${pdfPath}\n\nNote: Actual PDF conversion requires LibreOffice or PowerPoint.`; } private async handlePPTAddMedia(args: any): Promise<string> { const buffer = await this.pptGen.addMedia( args.filename, args.slideNumber, args.mediaPath, args.mediaType, args.position, args.size ); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Media embedded!**\n\nšŸŽ„ **Type:** ${args.mediaType}\nšŸ“Š **Slide:** ${args.slideNumber}\nšŸ“ **File:** ${fullPath}`; } // ========== OUTLOOK HANDLERS ========== private async handleOutlookSendEmail(args: any): Promise<string> { const result = await this.outlookGen.sendEmail(args); return `āœ… **Email processed!**\n\n${result}`; } private async handleOutlookCreateMeeting(args: any): Promise<string> { const ics = await this.outlookGen.createMeeting(args); const outputPath = args.outputPath || process.cwd(); const filename = `meeting_${Date.now()}.ics`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, ics, 'utf-8'); return `āœ… **Meeting created!**\n\nšŸ“… **Subject:** ${args.subject}\nā° **Start:** ${args.startTime}\nšŸ“ **ICS file:** ${fullPath}\n\nImport this file into Outlook/Google Calendar.`; } private async handleOutlookAddContact(args: any): Promise<string> { const vcf = await this.outlookGen.addContact(args); const outputPath = args.outputPath || process.cwd(); const filename = `contact_${args.lastName}_${args.firstName}.vcf`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, vcf, 'utf-8'); return `āœ… **Contact created!**\n\nšŸ‘¤ **Name:** ${args.firstName} ${args.lastName}\n${args.email ? `šŸ“§ **Email:** ${args.email}\n` : ''}šŸ“ **VCF file:** ${fullPath}\n\nImport this file into Outlook/Contacts app.`; } private async handleOutlookCreateTask(args: any): Promise<string> { const task = await this.outlookGen.createTask(args); const outputPath = args.outputPath || process.cwd(); const filename = `task_${Date.now()}.json`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, task, 'utf-8'); return `āœ… **Task created!**\n\nāœ… **Subject:** ${args.subject}\n${args.dueDate ? `šŸ“… **Due:** ${args.dueDate}\n` : ''}šŸ”¢ **Priority:** ${args.priority || 'normal'}\nšŸ“ **JSON file:** ${fullPath}`; } private async handleOutlookSetRule(args: any): Promise<string> { const rule = await this.outlookGen.setRule(args); const outputPath = args.outputPath || process.cwd(); const filename = `rule_${Date.now()}.json`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, rule, 'utf-8'); return `āœ… **Inbox rule created!**\n\nāš™ļø **Name:** ${args.name}\nšŸ”§ **Conditions:** ${args.conditions.length}\nšŸŽÆ **Actions:** ${args.actions.length}\nšŸ“ **JSON file:** ${fullPath}`; } // ========== EXCEL v3.0 HANDLERS ========== private async handleExcelAddSparklines(args: any): Promise<string> { const buffer = await this.excelGen.addSparklines(args.filename, args.sheetName, args.dataRange, args.location, args.type, args.options); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Sparklines added!**\n\n✨ **Type:** ${args.type}\nšŸ“ **Location:** ${args.location}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelArrayFormulas(args: any): Promise<string> { const buffer = await this.excelGen.addArrayFormulas(args.filename, args.sheetName, args.formulas); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Array formulas added!**\n\nšŸ”¢ **Count:** ${args.formulas.length}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelAddSubtotals(args: any): Promise<string> { const buffer = await this.excelGen.addSubtotals(args.filename, args.sheetName, args.range, args.groupBy, args.summaryFunction, args.summaryColumns); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Subtotals added!**\n\nšŸ“Š **Function:** ${args.summaryFunction}\nšŸ“ **Range:** ${args.range}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelAddHyperlinks(args: any): Promise<string> { const buffer = await this.excelGen.addHyperlinks(args.filename, args.sheetName, args.links); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Hyperlinks added!**\n\nšŸ”— **Count:** ${args.links.length}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelAdvancedCharts(args: any): Promise<string> { const buffer = await this.excelGen.addAdvancedChart(args.filename, args.sheetName, args.chart); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Advanced chart added!**\n\nšŸ“ˆ **Type:** ${args.chart.type}\nšŸ“Š **Title:** ${args.chart.title}\nšŸ“ **File:** ${fullPath}`; } private async handleExcelAddSlicers(args: any): Promise<string> { const buffer = await this.excelGen.addSlicers(args.filename, args.sheetName, args.tableName, args.slicers); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Slicers added!**\n\nšŸŽ›ļø **Count:** ${args.slicers.length}\nšŸ“Š **Table:** ${args.tableName}\nšŸ“ **File:** ${fullPath}`; } // ========== WORD v3.0 HANDLERS ========== private async handleWordTrackChanges(args: any): Promise<string> { const buffer = await this.wordGen.enableTrackChanges(args.filename, args.enable, args.author); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Track changes ${args.enable ? 'enabled' : 'disabled'}!**\n\nāœļø **Author:** ${args.author || 'Office Whisperer'}\nšŸ“ **File:** ${fullPath}`; } private async handleWordAddFootnotes(args: any): Promise<string> { const buffer = await this.wordGen.addFootnotes(args.filename, args.footnotes); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Footnotes added!**\n\nšŸ“Œ **Count:** ${args.footnotes.length}\nšŸ“ **File:** ${fullPath}`; } private async handleWordAddBookmarks(args: any): Promise<string> { const buffer = await this.wordGen.addBookmarks(args.filename, args.bookmarks); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Bookmarks added!**\n\nšŸ”– **Count:** ${args.bookmarks.length}\nšŸ“ **File:** ${fullPath}`; } private async handleWordAddSectionBreaks(args: any): Promise<string> { const buffer = await this.wordGen.addSectionBreaks(args.filename, args.breaks); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Section breaks added!**\n\nšŸ“„ **Count:** ${args.breaks.length}\nšŸ“ **File:** ${fullPath}`; } private async handleWordAddTextBoxes(args: any): Promise<string> { const buffer = await this.wordGen.addTextBoxes(args.filename, args.textBoxes); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Text boxes added!**\n\nšŸ“¦ **Count:** ${args.textBoxes.length}\nšŸ“ **File:** ${fullPath}`; } private async handleWordAddCrossReferences(args: any): Promise<string> { const buffer = await this.wordGen.addCrossReferences(args.filename, args.references); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Cross-references added!**\n\nšŸ”— **Count:** ${args.references.length}\nšŸ“ **File:** ${fullPath}`; } // ========== POWERPOINT v3.0 HANDLERS ========== private async handlePPTDefineMasterSlide(args: any): Promise<string> { const buffer = await this.pptGen.defineMasterSlide(args.filename, args.masterSlide); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Master slide defined!**\n\nšŸŽØ **Name:** ${args.masterSlide.name}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTAddHyperlinks(args: any): Promise<string> { const buffer = await this.pptGen.addHyperlinks(args.filename, args.slideNumber, args.links); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Hyperlinks added!**\n\nšŸ”— **Count:** ${args.links.length}\nšŸ“Š **Slide:** ${args.slideNumber}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTAddSections(args: any): Promise<string> { const buffer = await this.pptGen.addSections(args.filename, args.sections); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Sections added!**\n\nšŸ“ **Count:** ${args.sections.length}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTMorphTransition(args: any): Promise<string> { const buffer = await this.pptGen.addMorphTransition(args.filename, args.fromSlide, args.toSlide, args.duration); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Morph transition added!**\n\n✨ **From slide:** ${args.fromSlide}\n✨ **To slide:** ${args.toSlide}\nšŸ“ **File:** ${fullPath}`; } private async handlePPTAddActionButtons(args: any): Promise<string> { const buffer = await this.pptGen.addActionButtons(args.filename, args.slideNumber, args.buttons); const outputPath = args.outputPath || path.dirname(args.filename); const fullPath = path.join(outputPath, path.basename(args.filename)); await fs.writeFile(fullPath, buffer); return `āœ… **Action buttons added!**\n\nšŸ”˜ **Count:** ${args.buttons.length}\nšŸ“Š **Slide:** ${args.slideNumber}\nšŸ“ **File:** ${fullPath}`; } // ========== OUTLOOK v3.0 HANDLERS ========== private async handleOutlookReadEmails(args: any): Promise<string> { const result = await this.outlookGen.readEmails(args); return `āœ… **Email reading processed!**\n\n${result}`; } private async handleOutlookSearchEmails(args: any): Promise<string> { const result = await this.outlookGen.searchEmails(args); return `āœ… **Email search processed!**\n\n${result}`; } private async handleOutlookRecurringMeeting(args: any): Promise<string> { const ics = await this.outlookGen.createRecurringMeeting(args); const outputPath = args.outputPath || process.cwd(); const filename = `recurring_meeting_${Date.now()}.ics`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, ics, 'utf-8'); return `āœ… **Recurring meeting created!**\n\nšŸ“… **Subject:** ${args.subject}\nšŸ”„ **Frequency:** ${args.recurrence.frequency}\nšŸ“ **ICS file:** ${fullPath}`; } private async handleOutlookSaveTemplate(args: any): Promise<string> { const template = await this.outlookGen.saveEmailTemplate(args); const outputPath = args.outputPath || process.cwd(); const filename = `email_template_${args.name.replace(/\s+/g, '_')}.json`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, template, 'utf-8'); return `āœ… **Email template saved!**\n\nšŸ“§ **Name:** ${args.name}\nšŸ“ **File:** ${fullPath}`; } private async handleOutlookMarkRead(args: any): Promise<string> { const result = await this.outlookGen.markAsRead(args); return `āœ… **Mark read/unread processed!**\n\n${result}`; } private async handleOutlookArchiveEmail(args: any): Promise<string> { const result = await this.outlookGen.archiveEmail(args); return `āœ… **Archive processed!**\n\n${result}`; } private async handleOutlookCalendarView(args: any): Promise<string> { const result = await this.outlookGen.getCalendarView(args); const outputPath = args.outputPath || process.cwd(); const ext = args.outputFormat === 'json' ? 'json' : 'ics'; const filename = `calendar_view_${Date.now()}.${ext}`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, result, 'utf-8'); return `āœ… **Calendar view created!**\n\nšŸ“… **View:** ${args.viewType}\nšŸ“ **File:** ${fullPath}`; } private async handleOutlookSearchContacts(args: any): Promise<string> { const result = await this.outlookGen.searchContacts(args); const outputPath = args.outputPath || process.cwd(); const ext = args.outputFormat === 'json' ? 'json' : 'vcf'; const filename = `contacts_search_${Date.now()}.${ext}`; const fullPath = path.join(outputPath, filename); await fs.writeFile(fullPath, result, 'utf-8'); return `āœ… **Contact search completed!**\n\nšŸ” **Query:** ${args.query}\nšŸ“ **File:** ${fullPath}`; } } // Start the server const server = new OfficeWhispererServer(); server.start().catch(console.error);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/consigcody94/office-whisperer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server