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);