{"_id":"@mseep/mcp-web","name":"@mseep/mcp-web","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"type":"commonjs","name":"@mseep/mcp-web","version":"0.1.0","description":"Microsoft Cloud Platform Web Client","scripts":{"dev:web":"NODE_ENV=development node src/main/dev-server.cjs","dev:api":"node src/main/server.cjs","start":"NODE_ENV=production MCP_SILENT_MODE=true node src/main/dev-server.cjs","reset-db":"node scripts/reset-database.js","setup":"node scripts/setup-project.js","postinstall":"node scripts/setup-project.js"},"dependencies":{"@azure/msal-node":"^2.16.2","@microsoft/microsoft-graph-client":"^3.0.7","@npmcli/fs":"^3.1.0","axios":"^1.6.2","body-parser":"^2.2.2","cors":"^2.8.5","docx":"^9.6.1","dotenv":"^16.5.0","express":"^4.18.2","express-rate-limit":"^7.5.0","express-session":"^1.18.1","fs-extra":"^11.2.0","helmet":"^7.2.0","http-proxy-middleware":"^3.0.5","joi":"^17.13.3","jsonwebtoken":"^9.0.2","jszip":"^3.10.1","lru-cache":"^10.0.1","mammoth":"^1.12.0","memorystore":"^1.6.7","moment":"^2.29.4","morgan":"^1.10.0","mysql2":"^3.11.0","node-cache":"^5.1.2","node-fetch":"^2.7.0","node-gyp":"^11.2.0","pg":"^8.11.3","pg-pool":"^3.6.2","pptxgenjs":"^4.0.1","sqlite3":"^5.1.6","uuid":"^9.0.1","winston":"^3.17.0","word-extractor":"^1.0.4","xml2js":"^0.6.2"},"devDependencies":{"@babel/core":"^7.26.10","@babel/preset-env":"^7.26.9","concurrently":"^8.2.2","nodemon":"^3.0.2","serve":"^14.2.0","standard":"^17.1.0"},"overrides":{"glob":"^10.3.10","rimraf":"^5.0.5","boolean":"^3.2.0","npmlog":"^7.0.1","are-we-there-yet":"^4.0.0","gauge":"^5.0.0","@npmcli/move-file":"@npmcli/fs","eslint":"npm:standard@^17.1.0"},"engines":{"node":">=18.0.0"},"keywords":["mseep","mcp-server"],"publisher":"mseep","_id":"@mseep/mcp-web@0.1.0","gitHead":"f5686fc37584c1ca3512a8696bfb0a64664a61bd","_nodeVersion":"18.20.8","_npmVersion":"10.8.2","dist":{"integrity":"sha512-O6OM/ozxMgndF8Vq/yCxYcnHLGQWR2j61nZU7k5y1uHmIKyFN3UPGZWV6J6p1Iqhfz+vCNy/cwU0NUL2JZZFwQ==","shasum":"0089c4192af0681db408ea10e24d32485b20527d","tarball":"https://registry.npmjs.org/@mseep/mcp-web/-/mcp-web-0.1.0.tgz","fileCount":104,"unpackedSize":3237208,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDML7YSz+b0Lvt8XsIvvOdZwlKhCaUEw4mA/FwQz4Zq0gIgYh78ZR9E9hENiqTFsRSZDWkt/VtYtxxQ51nLdVwMK2c="}]},"_npmUser":{"name":"skydeckai","email":"support@skydeck.ai"},"directories":{},"maintainers":[{"name":"skydeckai","email":"support@skydeck.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-web_0.1.0_1782112188427_0.3447513454822675"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-22T07:09:48.274Z","0.1.0":"2026-06-22T07:09:48.599Z","modified":"2026-06-22T07:09:48.818Z"},"maintainers":[{"name":"skydeckai","email":"support@skydeck.ai"}],"description":"Microsoft Cloud Platform Web Client","keywords":["mseep","mcp-server"],"readme":"[![MseeP.ai Security Assessment Badge](https://mseep.net/pr/aanerud-mcp-microsoft-office-badge.png)](https://mseep.ai/app/aanerud-mcp-microsoft-office)\n\n# MCP Microsoft Office\n\n**One MCP server. Multiple users. Real Microsoft 365 traffic on your test tenant.**\n\n---\n\n## The Problem\n\nTest tenants sit empty. Static test data does not exercise real workflows. When you need agents that send real emails, schedule real meetings, and collaborate in real Teams channels, mocks and stubs fall short.\n\n## What This Solves\n\nThis project connects any MCP-compatible AI client to Microsoft 365 through the Graph API. Each agent authenticates as a distinct tenant user and performs real operations against real data.\n\n- **117 tools** across 12 modules: Mail, Calendar, Files, **Excel**, **Word**, **PowerPoint**, Teams, Contacts, To-Do, Groups, People, Search\n- **Multi-user**: one server supports your entire team, each with isolated data\n- **Real Graph API calls**: every operation hits the actual tenant, not a mock\n- **Secure**: tokens encrypted at rest, no credentials stored on third-party servers\n\n---\n\n## Architecture\n\n```\n                    ┌──────────────────┐\n                    │  MCP Client      │\n                    │  (Claude, etc.)  │\n                    └────────┬─────────┘\n                             │ JSON-RPC (stdin/stdout)\n                    ┌────────▼─────────┐\n                    │  MCP Adapter     │\n                    │  (runs locally)  │\n                    └────────┬─────────┘\n                             │ HTTP + Bearer Token\n                    ┌────────▼─────────┐\n                    │  MCP Server      │\n                    │  (local or       │\n                    │   remote)        │\n                    └────────┬─────────┘\n                             │ Microsoft Graph API\n                    ┌────────▼─────────┐\n                    │  Microsoft 365   │\n                    │  (your tenant)   │\n                    └──────────────────┘\n```\n\n**Three parts:**\n\n1. **MCP Client** -- the AI you interact with\n2. **MCP Adapter** -- a Node.js process that translates MCP protocol to HTTP requests (runs on the same machine as the client)\n3. **MCP Server** -- handles authentication and calls the Microsoft Graph API (runs locally or on a remote server)\n\n---\n\n## Permissions\n\nThe server requires 18 Microsoft Graph delegated permissions. Twelve work without admin consent. Six require a tenant administrator to grant consent.\n\n### No Admin Consent Required\n\n| Permission | Tools Unlocked |\n|---|---|\n| `User.Read` | Authentication, user profile |\n| `Mail.ReadWrite` | readMail, readMailDetails, markEmailRead, flagMail, getMailAttachments, addMailAttachment, removeMailAttachment |\n| `Mail.Send` | sendMail, replyToMail |\n| `Calendars.ReadWrite` | getEvents, createEvent, updateEvent, cancelEvent, acceptEvent, tentativelyAcceptEvent, declineEvent, getAvailability, findMeetingTimes, getRooms, getCalendars, addAttachment, removeAttachment |\n| `Files.ReadWrite.All` | listFiles, uploadFile, downloadFile, getFileMetadata, getFileContent, setFileContent, updateFileContent, createSharingLink, getSharingLinks, removeSharingPermission, listChannelFiles, uploadFileToChannel, readChannelFile, **all Excel workbook tools**, **all Word/PowerPoint tools** |\n| `Contacts.ReadWrite` | listContacts, getContact, createContact, updateContact, deleteContact, searchContacts |\n| `Tasks.ReadWrite` | listTaskLists, getTaskList, createTaskList, updateTaskList, deleteTaskList, listTasks, getTask, createTask, updateTask, deleteTask, completeTask |\n| `Chat.ReadWrite` | listChats, createChat, getChatMessages, sendChatMessage |\n| `Channel.ReadBasic.All` | listTeamChannels, getChannelMessages |\n| `ChannelMessage.Send` | sendChannelMessage, replyToMessage |\n| `Channel.Create` | createTeamChannel |\n| `OnlineMeetings.ReadWrite` | createOnlineMeeting, getOnlineMeeting, listOnlineMeetings, getMeetingByJoinUrl |\n\n### Requires Admin Consent\n\n| Permission | Additional Tools Unlocked |\n|---|---|\n| `User.Read.All` | Resolve user IDs across Teams, People search |\n| `People.Read.All` | findPeople, getRelevantPeople, getPersonById |\n| `Group.Read.All` | listGroups, getGroup, listGroupMembers, listMyGroups |\n| `ChannelMember.ReadWrite.All` | addChannelMember |\n| `ChannelMessage.Read.All` | Read channel message history |\n| `OnlineMeetingTranscript.Read.All` | getMeetingTranscripts, getMeetingTranscriptContent |\n\n**Without admin consent**, you get Mail, Calendar, Files, Excel workbooks, Word documents, PowerPoint presentations, Contacts, To-Do, Chat, and basic Teams channel operations. **With admin consent**, you add People directory search, Groups, channel member management, and meeting transcripts.\n\n---\n\n## Quick Start\n\n### Prerequisites\n\n- **Node.js 18+** ([download](https://nodejs.org/))\n- **Claude Desktop** ([download](https://claude.ai/download)) or another MCP client\n- **Microsoft 365 account** (work, school, or personal)\n\n### Step 1: Azure App Registration\n\n1. Go to [Azure Portal](https://portal.azure.com) > **Microsoft Entra ID** > **App registrations** > **New registration**\n2. Name it `MCP-Microsoft-Office`, register with your preferred account type\n3. Copy the **Application (client) ID** and **Directory (tenant) ID**\n4. Go to **API permissions** > **Add a permission** > **Microsoft Graph** > **Delegated permissions**\n5. Add the 18 permissions listed above\n6. If you are a tenant admin, click **Grant admin consent**\n7. Go to **Authentication** > **Add a platform** > **Web**\n   - Redirect URI: `http://localhost:3000/api/auth/callback`\n   - Enable **Allow public client flows**\n\n### Step 2: Clone and Configure\n\n```bash\ngit clone https://github.com/Aanerud/MCP-Microsoft-Office.git\ncd MCP-Microsoft-Office\nnpm install\n```\n\nCopy `.env.example` to `.env` and fill in your Azure app details:\n\n```\nMICROSOFT_CLIENT_ID=your-client-id\nMICROSOFT_TENANT_ID=your-tenant-id\n```\n\n### Step 3: Start the Server and Authenticate\n\n```bash\nnpm run dev:web\n```\n\nOpen `http://localhost:3000` in your browser. Click **Login with Microsoft**, sign in, and grant permissions. Then click **Generate MCP Token** and copy the token.\n\n### Step 4: Configure Claude Desktop\n\nEdit your Claude Desktop config:\n\n**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`\n**Windows**: `%APPDATA%\\Claude\\claude_desktop_config.json`\n\nClaude Desktop has a practical limit of ~55 tools per MCP server. This project exposes 117 tools, so we split them across three servers that share the same adapter and backend:\n\n```json\n{\n  \"mcpServers\": {\n    \"microsoft-365\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/MCP-Microsoft-Office/mcp-adapter.cjs\"],\n      \"env\": {\n        \"MCP_SERVER_URL\": \"http://localhost:3000\",\n        \"MCP_BEARER_TOKEN\": \"paste-your-token-here\",\n        \"MCP_MODULES\": \"search,mail,calendar,files,people,contacts,groups,query\"\n      }\n    },\n    \"microsoft-365-teams\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/MCP-Microsoft-Office/mcp-adapter.cjs\"],\n      \"env\": {\n        \"MCP_SERVER_URL\": \"http://localhost:3000\",\n        \"MCP_BEARER_TOKEN\": \"paste-your-token-here\",\n        \"MCP_MODULES\": \"teams,todo\"\n      }\n    },\n    \"microsoft-365-office\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/MCP-Microsoft-Office/mcp-adapter.cjs\"],\n      \"env\": {\n        \"MCP_SERVER_URL\": \"http://localhost:3000\",\n        \"MCP_BEARER_TOKEN\": \"paste-your-token-here\",\n        \"MCP_MODULES\": \"excel,word,powerpoint,files\"\n      }\n    }\n  }\n}\n```\n\n`MCP_MODULES` filters which modules the adapter exposes. Omit it to expose all 117 tools (works with clients that have no tool cap).\n\nSet `MCP_DEBUG=1` in the `env` block to enable diagnostic logging to stderr — useful for troubleshooting tool dispatch issues.\n\nRestart Claude Desktop. Ask: *\"What's on my calendar today?\"* or *\"Create an Excel workbook with a budget table.\"*\n\n---\n\n## Tools (117)\n\n### Mail (9)\n\n| Tool | Description |\n|---|---|\n| `readMail` | Read inbox messages |\n| `sendMail` | Send an email |\n| `replyToMail` | Reply to an email |\n| `readMailDetails` | Get full email content |\n| `markEmailRead` | Mark email as read/unread |\n| `flagMail` | Flag or unflag an email |\n| `getMailAttachments` | List email attachments |\n| `addMailAttachment` | Add attachment to email |\n| `removeMailAttachment` | Remove attachment from email |\n\n### Calendar (13)\n\n| Tool | Description |\n|---|---|\n| `getEvents` | Get calendar events |\n| `createEvent` | Create a meeting or event |\n| `updateEvent` | Modify an existing event |\n| `cancelEvent` | Cancel an event |\n| `acceptEvent` | Accept a meeting invitation |\n| `tentativelyAcceptEvent` | Tentatively accept |\n| `declineEvent` | Decline a meeting invitation |\n| `getAvailability` | Check free/busy times |\n| `findMeetingTimes` | Find optimal meeting slots |\n| `getRooms` | Find meeting rooms |\n| `getCalendars` | List all calendars |\n| `addAttachment` | Add attachment to event |\n| `removeAttachment` | Remove event attachment |\n\n### Files (10)\n\n| Tool | Description |\n|---|---|\n| `listFiles` | List OneDrive files |\n| `uploadFile` | Upload a file |\n| `downloadFile` | Download a file |\n| `getFileMetadata` | Get file info |\n| `getFileContent` | Read file contents |\n| `setFileContent` | Write file contents |\n| `updateFileContent` | Update existing file |\n| `createSharingLink` | Create a sharing link |\n| `getSharingLinks` | List sharing links |\n| `removeSharingPermission` | Remove sharing access |\n\n### Excel (30)\n\nWork directly with Excel workbooks stored in OneDrive or SharePoint — no file download needed. All operations go through Microsoft Graph's workbook API with transparent session management.\n\n| Tool | Description |\n|---|---|\n| `createWorkbookSession` | Open a workbook session (persistent or temporary) |\n| `closeWorkbookSession` | Close an active workbook session |\n| `listWorksheets` | List all worksheets in a workbook |\n| `addWorksheet` | Add a new worksheet |\n| `getWorksheet` | Get a worksheet by name or ID |\n| `updateWorksheet` | Rename, reposition, or hide a worksheet |\n| `deleteWorksheet` | Delete a worksheet |\n| `getRange` | Read cell values, formulas, and formatting |\n| `updateRange` | Write values to a cell range |\n| `getRangeFormat` | Get formatting (font, fill, borders) |\n| `updateRangeFormat` | Set formatting (bold, colors, number formats) |\n| `sortRange` | Sort cells in a range |\n| `mergeRange` | Merge cells |\n| `unmergeRange` | Unmerge cells |\n| `listTables` | List all tables in a worksheet |\n| `createTable` | Create a table from a range |\n| `updateTable` | Rename or restyle a table |\n| `deleteTable` | Delete a table |\n| `listTableRows` | List all rows in a table |\n| `addTableRow` | Add a row to a table |\n| `deleteTableRow` | Delete a row by index |\n| `listTableColumns` | List all columns in a table |\n| `addTableColumn` | Add a column to a table |\n| `deleteTableColumn` | Delete a column |\n| `sortTable` | Sort a table by column |\n| `filterTable` | Apply a filter to a table column |\n| `clearTableFilter` | Clear a column filter |\n| `convertTableToRange` | Convert a table back to a plain range |\n| `callWorkbookFunction` | Call any of 300+ Excel functions (SUM, VLOOKUP, PMT, etc.) |\n| `calculateWorkbook` | Recalculate all formulas |\n\n### Word (5)\n\nCreate, read, and convert Word documents. Documents are created from structured JSON and stored in OneDrive. Reading uses a multi-library fallback chain: mammoth (best HTML for .docx) → word-extractor (handles both .doc and .docx) → webUrl fallback. Binary downloads use the Graph beta `/contentStream` endpoint for reliable binary transfer.\n\n| Tool | Description |\n|---|---|\n| `createWordDocument` | Create a .docx from structured content (headings, paragraphs, tables, lists, images) |\n| `readWordDocument` | Read a document as HTML and plain text |\n| `getWordDocumentMetadata` | Get title, author, dates, keywords |\n| `getWordDocumentAsHtml` | Convert document content to HTML |\n| `convertDocumentToPdf` | Convert a Word document to PDF |\n\n> **Note:** Some SharePoint tenants convert uploaded .docx files to OLE2 binary format within seconds of upload. When this happens, client-side parsing libraries cannot read the file. The server gracefully falls back to returning the `webUrl` so the user can open the document in the browser.\n\n### PowerPoint (4)\n\nCreate, read, and convert PowerPoint presentations. Presentations are built from structured slide data and stored in OneDrive. Reading uses Graph HTML conversion with jszip fallback for slide-level text extraction.\n\n| Tool | Description |\n|---|---|\n| `createPresentation` | Create a .pptx with title, content, and blank slides |\n| `readPresentation` | Read slide content (text elements per slide) |\n| `getPresentationMetadata` | Get title, author, slide count, dates |\n| `convertPresentationToPdf` | Convert a presentation to PDF |\n\n### Teams (21)\n\n| Tool | Description |\n|---|---|\n| `listChats` | List Teams chats |\n| `createChat` | Create a new chat |\n| `getChatMessages` | Read chat messages |\n| `sendChatMessage` | Send a chat message |\n| `listJoinedTeams` | List your teams |\n| `listTeamChannels` | List team channels |\n| `createTeamChannel` | Create a channel |\n| `addChannelMember` | Add member to channel |\n| `getChannelMessages` | Read channel messages |\n| `sendChannelMessage` | Post to a channel |\n| `replyToMessage` | Reply to a channel message |\n| `listChannelFiles` | List files in a channel |\n| `uploadFileToChannel` | Upload file to channel |\n| `readChannelFile` | Read a channel file |\n| `createOnlineMeeting` | Create a Teams meeting |\n| `getOnlineMeeting` | Get meeting details |\n| `listOnlineMeetings` | List online meetings |\n| `getMeetingByJoinUrl` | Find meeting by join URL |\n| `getMeetingTranscripts` | Get meeting transcripts |\n| `getMeetingTranscriptContent` | Read transcript content |\n\n*(Note: `addChannelMember` applies to private channels only. Standard channels auto-include all team members.)*\n\n### Contacts (6)\n\n| Tool | Description |\n|---|---|\n| `listContacts` | List contacts |\n| `getContact` | Get contact details |\n| `createContact` | Create a contact |\n| `updateContact` | Update contact info |\n| `deleteContact` | Delete a contact |\n| `searchContacts` | Search contacts |\n\n### To-Do (11)\n\n| Tool | Description |\n|---|---|\n| `listTaskLists` | List task lists |\n| `getTaskList` | Get a task list |\n| `createTaskList` | Create a task list |\n| `updateTaskList` | Rename a task list |\n| `deleteTaskList` | Delete a task list |\n| `listTasks` | List tasks |\n| `getTask` | Get task details |\n| `createTask` | Create a task |\n| `updateTask` | Update a task |\n| `deleteTask` | Delete a task |\n| `completeTask` | Mark task complete |\n\n### Groups (4)\n\n| Tool | Description |\n|---|---|\n| `listGroups` | List Microsoft 365 groups |\n| `getGroup` | Get group details |\n| `listGroupMembers` | List group members |\n| `listMyGroups` | List your groups |\n\n### People (3)\n\n| Tool | Description |\n|---|---|\n| `findPeople` | Search the directory |\n| `getRelevantPeople` | Get frequent contacts |\n| `getPersonById` | Get person details |\n\n### Search (1)\n\n| Tool | Description |\n|---|---|\n| `search` | Unified search across emails, files, events, and chat messages |\n\n---\n\n## Multi-User\n\nEach user authenticates independently. The server isolates all data by user identity.\n\n```\n  Alice (alice@contoso.com)          Bob (bob@contoso.com)\n  ├─ Her own Microsoft tokens        ├─ His own Microsoft tokens\n  ├─ Her own session                  ├─ His own session\n  └─ Claude Desktop (her laptop)     └─ Claude Desktop (his PC)\n\n              Complete data isolation.\n         Alice never sees Bob's data.\n```\n\nFor **automated testing with multiple agents**, use the ROPC (Resource Owner Password Credentials) flow to authenticate programmatically:\n\n```bash\n# Start the server\nnpm run dev:web\n\n# Run the E2E test suite (authenticates 3 users via ROPC)\nnode tests/run-all.cjs\n```\n\nThe test suite authenticates multiple users, then exercises all 117 tools across 12 modules plus 5 cross-module workflows. See `tests/` for the full implementation.\n\n---\n\n## E2E Test Suite\n\nThe project includes a comprehensive test suite covering all 117 tools.\n\n```bash\n# Run all tests (requires server running)\nnode tests/run-all.cjs\n\n# Run a single module\nnode tests/run-all.cjs --bucket mail --buckets-only\n\n# Run only workflows\nnode tests/run-all.cjs --workflows-only\n```\n\n**Test structure:**\n\n```\ntests/\n  lib/           Shared auth, HTTP client, reporter\n  buckets/       One file per module (12 files, 117 tools)\n  workflows/     Cross-module tests (5 files)\n  run-all.cjs    Master runner\n```\n\nTests authenticate via ROPC (no manual token management) and run in ~100 seconds.\n\n---\n\n## Environment Variables\n\nCopy `.env.example` to `.env` and configure:\n\n| Variable | Required | Description |\n|---|---|---|\n| `MICROSOFT_CLIENT_ID` | Yes | Azure App Client ID |\n| `MICROSOFT_TENANT_ID` | Yes | Azure Tenant ID |\n| `MICROSOFT_REDIRECT_URI` | No | OAuth callback URL (default: `http://localhost:3000/api/auth/callback`) |\n| `DEVICE_REGISTRY_ENCRYPTION_KEY` | Production | 32-byte encryption key for token storage |\n| `JWT_SECRET` | Production | Secret for signing JWT tokens |\n| `CORS_ALLOWED_ORIGINS` | Production | Comma-separated allowed origins |\n| `PORT` | No | Server port (default: `3000`) |\n| `NODE_ENV` | No | `development` or `production` |\n\n---\n\n## Deployment\n\n### Local (Recommended for Getting Started)\n\n```bash\nnpm install\nnpm run dev:web\n```\n\n### Azure App Service\n\nSee [docs/azure-deployment.md](docs/azure-deployment.md) for CI/CD deployment with GitHub Actions.\n\n---\n\n## Security\n\n- **Encrypted storage**: all Microsoft tokens encrypted at rest with AES-256\n- **No client secrets**: uses public client flow (PKCE) for desktop authentication\n- **Token isolation**: each user's tokens stored separately with different encryption keys\n- **Rate limiting**: built-in rate limiting protects against abuse\n- **CORS protection**: origin allowlist in production\n- **Session expiry**: sessions expire after 24 hours\n\n### Production Checklist\n\n- [ ] Set `NODE_ENV=production`\n- [ ] Set `DEVICE_REGISTRY_ENCRYPTION_KEY` (32 bytes)\n- [ ] Set `JWT_SECRET` (strong random string)\n- [ ] Set `CORS_ALLOWED_ORIGINS`\n- [ ] Use HTTPS with a valid certificate\n\n---\n\n## Project Structure\n\n```\nMCP-Microsoft-Office/\n├── mcp-adapter.cjs          MCP protocol adapter (runs locally with Claude Desktop)\n├── src/\n│   ├── api/                 Express routes and controllers\n│   ├── auth/                MSAL authentication (OAuth2, ROPC, token exchange)\n│   ├── core/                Services (cache, storage, tools, error handling)\n│   ├── graph/               Microsoft Graph API services\n│   │   ├── graph-client.cjs   HTTP client with retry, binary support, sessions\n│   │   ├── files-service.cjs  OneDrive file operations\n│   │   ├── excel-service.cjs  Workbook API (sessions, ranges, tables, functions)\n│   │   ├── word-service.cjs   Word create/read (docx + mammoth + word-extractor)\n│   │   └── powerpoint-service.cjs  PPT create/read (pptxgenjs + jszip)\n│   └── modules/             Feature modules (mail, calendar, excel, word, powerpoint, etc.)\n├── public/                  Web UI for authentication\n└── tests/                   E2E test suite (gitignored)\n```\n\n---\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Submit a pull request\n\n---\n\n## License\n\nMIT License -- see [LICENSE](LICENSE) file.\n","readmeFilename":"README.md","_rev":"1-4376bc1768ca83a8c2ec932abe30f1ed"}