Microsoft 365
Connect your agents to Microsoft 365 for Outlook email, OneDrive, Office documents (Word, Excel, PowerPoint), Calendar, Teams, and SharePoint.
48 tools across 10 Microsoft services.
Outlook (8 tools)
| Tool | Description |
|---|---|
outlook_send | Send email via the agent's assigned Microsoft 365 email address |
outlook_list | List emails from a mailbox folder with OData filtering |
outlook_read | Read the full content of an email by message ID |
outlook_search | Full-text search emails using KQL syntax |
outlook_reply | Reply or reply-all to an email |
outlook_forward | Forward an email to other recipients |
outlook_move | Move an email to a different folder |
outlook_delete | Delete an email (moves to Deleted Items) |
Send Email
await tools.outlook_send({
to: 'customer@example.com',
subject: 'Re: Your inquiry',
body: 'Thank you for reaching out...',
cc: 'team@company.com',
importance: 'normal' // low, normal, high
});
// Returns
{
success: true,
sent: true,
sentAs: 'agent@company.com'
}
The body field supports HTML content. Multiple recipients can be comma-separated in to, cc, and bcc.
List Emails
const emails = await tools.outlook_list({
folder: 'inbox', // default: "inbox"
filter: 'isRead eq false',
maxResults: 10, // max: 100
orderBy: 'receivedDateTime desc'
});
// Returns
{
success: true,
emails: [
{
id: 'AAMk...',
subject: 'Your ticket #1234',
from: 'support@company.com',
to: ['agent@company.com'],
receivedDateTime: '2026-02-10T10:30:00Z',
isRead: false,
preview: 'We have received your request...'
}
],
count: 3,
mailbox: 'agent@company.com'
}
The filter parameter accepts OData filter expressions such as isRead eq false, from/emailAddress/address eq 'user@example.com', etc.
Search Emails
const results = await tools.outlook_search({
query: 'from:alice subject:quarterly report',
maxResults: 10
});
Search uses KQL (Keyword Query Language) for full-text search across subjects, bodies, and senders.
Reply and Forward
// Reply to a specific email
await tools.outlook_reply({
messageId: 'AAMk...',
body: 'Thanks for the update!',
replyAll: false // true to reply-all
});
// Forward an email
await tools.outlook_forward({
messageId: 'AAMk...',
to: 'colleague@company.com',
comment: 'FYI - see below'
});
Move and Delete
// Move to archive
await tools.outlook_move({
messageId: 'AAMk...',
destinationFolder: 'archive' // or: drafts, deleteditems, junkemail, or a folder ID
});
// Delete (moves to Deleted Items)
await tools.outlook_delete({ messageId: 'AAMk...' });
OneDrive (7 tools)
| Tool | Description |
|---|---|
onedrive_list | List files and folders |
onedrive_search | Search files by name or content |
onedrive_read | Read/download file content (text or base64) |
onedrive_upload | Upload a file (text or base64, up to 4 MB) |
onedrive_create_folder | Create a folder |
onedrive_share | Share a file or folder with another user |
onedrive_delete | Delete a file or folder |
List Files
const files = await tools.onedrive_list({
path: '/Documents/Projects', // optional, defaults to root
maxResults: 20 // max: 100
});
// Returns
{
success: true,
files: [
{
id: 'item-123',
name: 'Q4 Report.docx',
size: 245678,
createdDateTime: '2026-01-01T00:00:00Z',
lastModifiedDateTime: '2026-02-10T10:00:00Z',
webUrl: 'https://company-my.sharepoint.com/...',
isFolder: false,
mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
}
],
count: 5,
owner: 'agent@company.com'
}
Search Files
const files = await tools.onedrive_search({
query: 'budget 2026',
maxResults: 10
});
Read and Upload Files
// Read a file (text files return content, binary files return base64)
const file = await tools.onedrive_read({ itemId: 'item-123' });
// file.content = "file content...", file.encoding = "text" or "base64"
// Upload a text file
await tools.onedrive_upload({
name: 'notes.txt',
content: 'Meeting notes from today...',
parentPath: '/Documents'
});
// Upload a binary file (base64)
await tools.onedrive_upload({
name: 'chart.png',
content: base64Content,
parentPath: '/Images',
isBase64: true
});
Max 10 MB for reads, 4 MB for simple uploads.
Create, Share, Delete
// Create a folder
await tools.onedrive_create_folder({
name: 'Q1 Reports',
parentPath: '/Documents'
});
// Share a file
await tools.onedrive_share({
itemId: 'item-123',
email: 'colleague@company.com',
role: 'write', // read, write
message: 'Here is the report'
});
// Delete
await tools.onedrive_delete({ itemId: 'item-123' });
Office Document Creation (3 tools)
Create new Office documents in OneDrive. Documents can be opened in Office Online for editing.
| Tool | Description |
|---|---|
word_create | Create a new Word document (.docx) |
excel_create | Create a new Excel spreadsheet (.xlsx) |
powerpoint_create | Create a new PowerPoint presentation (.pptx) |
// Create a Word document
const doc = await tools.word_create({
name: 'Meeting Notes',
parentPath: '/Documents'
});
// doc.document.webUrl → opens in Word Online
// Create an Excel spreadsheet
const sheet = await tools.excel_create({
name: 'Sales Pipeline',
parentPath: '/Finance'
});
// Create a PowerPoint presentation
const pres = await tools.powerpoint_create({
name: 'Q4 Review',
parentPath: '/Presentations'
});
Extensions are added automatically. All documents return id, name, and webUrl for Office Online editing.
Rich Document Creation (3 tools)
Generate professional, content-rich Office documents and save them directly to OneDrive. These tools use server-side rendering (PptxGenJS, docx, ExcelJS) to produce fully formatted files — no templates needed.
| Tool | Description |
|---|---|
powerpoint_create_deck | Create a presentation with multiple slides, layouts, and speaker notes |
word_create_document | Create a document with sections, headings, paragraphs, bullets, and tables |
excel_create_workbook | Create a multi-sheet workbook with headers, data rows, and column sizing |
Create a Presentation
const deck = await tools.powerpoint_create_deck({
fileName: 'Q4 Review',
slides: [
{
title: 'Q4 2025 Business Review',
subtitle: 'Prepared by Strategy Team',
layout: 'title'
},
{
title: 'Revenue Highlights',
body: 'Total revenue grew 45% year-over-year.',
bullets: [
'ARR reached $12M',
'Net retention at 135%',
'48 new enterprise accounts'
],
notes: 'Emphasize NRR improvement vs Q3',
layout: 'content'
},
{
title: 'Regional Breakdown',
body: 'North America leads, EMEA accelerating',
layout: 'two-column'
},
{
title: 'Next Steps',
layout: 'section'
}
],
parentPath: '/Presentations'
});
// deck.file.webUrl → opens in PowerPoint Online
Available layouts: title, content, section, two-column, blank
Each slide supports title, subtitle, body, bullets (array of strings), notes (speaker notes), and layout.
Create a Word Document
const doc = await tools.word_create_document({
fileName: 'Project Charter',
sections: [
{
heading: 'Project Overview',
headingLevel: 1,
paragraphs: [
'This document outlines the charter for Project Alpha.',
'The project aims to deliver a unified customer portal by Q2 2026.'
]
},
{
heading: 'Objectives',
headingLevel: 2,
bullets: [
'Reduce support tickets by 40%',
'Improve NPS from 32 to 50',
'Consolidate 3 legacy portals into one'
]
},
{
heading: 'Timeline',
headingLevel: 2,
table: {
headers: ['Phase', 'Start', 'End', 'Owner'],
rows: [
['Discovery', '2026-01-15', '2026-02-15', 'Product'],
['Design', '2026-02-15', '2026-03-30', 'UX'],
['Build', '2026-04-01', '2026-06-30', 'Engineering']
]
}
}
],
parentPath: '/Documents/Charters'
});
Each section supports heading, headingLevel (1-4), paragraphs (array of strings), bullets (array of strings), and table (with headers and rows).
Create an Excel Workbook
const workbook = await tools.excel_create_workbook({
fileName: 'Sales Pipeline Q1',
sheets: [
{
name: 'Pipeline',
headers: ['Company', 'Deal Size', 'Stage', 'Close Date', 'Owner'],
rows: [
['Acme Corp', '$120,000', 'Negotiation', '2026-03-15', 'Alice'],
['Globex', '$85,000', 'Proposal', '2026-04-01', 'Bob'],
['Initech', '$200,000', 'Discovery', '2026-05-15', 'Charlie']
],
columnWidths: [25, 15, 15, 15, 15]
},
{
name: 'Summary',
headers: ['Metric', 'Value'],
rows: [
['Total Pipeline', '$405,000'],
['Weighted Pipeline', '$187,500'],
['Deals in Stage', '3']
]
}
],
parentPath: '/Finance'
});
Each sheet supports name, headers (array of column names), rows (2D array of values), and optional columnWidths (array of numbers).
Excel Data (4 tools)
Read and write spreadsheet data via the Microsoft Graph Workbook API.
| Tool | Description |
|---|---|
excel_read | Read data from a cell range |
excel_write | Write data to cells |
excel_append | Append rows to a named table |
excel_create_table | Create a named table from a range |
Read Spreadsheet Data
const data = await tools.excel_read({
fileId: 'file-123', // OneDrive file ID
worksheet: 'Sheet1',
range: 'A1:D10'
});
// Returns
{
success: true,
values: [
['Name', 'Email', 'Department', 'Start Date'],
['Alice', 'alice@company.com', 'Engineering', '2023-01-15'],
['Bob', 'bob@company.com', 'Sales', '2023-03-01']
],
metadata: {
address: 'Sheet1!A1:D10',
rowCount: 3,
columnCount: 4
}
}
Write to Cells
await tools.excel_write({
fileId: 'file-123',
worksheet: 'Sheet1',
range: 'A11',
values: [
['Charlie', 'charlie@company.com', 'Marketing', '2024-01-15']
]
});
Tables: Create and Append
// Create a named table from existing data
await tools.excel_create_table({
fileId: 'file-123',
worksheet: 'Sheet1',
range: 'A1:D5',
hasHeaders: true,
name: 'EmployeeTable'
});
// Append rows to the table
await tools.excel_append({
fileId: 'file-123',
tableName: 'EmployeeTable',
values: [
['Diana', 'diana@company.com', 'Finance', '2024-06-01'],
['Eve', 'eve@company.com', 'Legal', '2024-07-15']
]
});
Calendar (2 tools)
| Tool | Description |
|---|---|
ms_calendar_list_events | List upcoming events from the agent's Outlook calendar |
ms_calendar_create_event | Create a calendar event with optional Teams meeting |
List Events
const events = await tools.ms_calendar_list_events({
maxResults: 10,
startDateTime: '2026-02-10T00:00:00Z',
endDateTime: '2026-02-17T00:00:00Z'
});
// Returns events with attendees, location, Teams join URL if applicable
Create Event
const event = await tools.ms_calendar_create_event({
subject: 'Project Kickoff',
body: '<p>Initial planning session</p>',
startDateTime: '2026-02-15T14:00:00Z',
endDateTime: '2026-02-15T15:00:00Z',
attendees: ['alice@company.com', 'bob@company.com'],
location: 'Conference Room A',
isOnlineMeeting: true // Automatically adds Teams meeting link
});
Set isOnlineMeeting: true to attach a Teams meeting link to the event.
Teams (5 tools)
| Tool | Description |
|---|---|
teams_create_meeting | Create a Teams meeting with join link |
teams_list_channels | List channels in a team |
teams_send | Send a message to a Teams channel |
teams_reply | Reply to a message in a channel |
teams_list_members | List members of a team |
Create Meeting
const meeting = await tools.teams_create_meeting({
subject: 'Quick Sync',
startDateTime: '2026-02-15T14:00:00Z', // omit for instant meeting
endDateTime: '2026-02-15T14:30:00Z',
attendees: ['alice@company.com']
});
// meeting.meeting.joinUrl → Teams meeting link
Channel Messaging
// List channels
const channels = await tools.teams_list_channels({ teamId: 'group-123' });
// Send a message
const msg = await tools.teams_send({
teamId: 'group-123',
channelId: 'channel-456',
content: 'Hello team! Here is the update...',
contentType: 'text' // or 'html'
});
// Reply to a message
await tools.teams_reply({
teamId: 'group-123',
channelId: 'channel-456',
messageId: msg.message.id,
content: 'Thanks for the update!'
});
List Members
const members = await tools.teams_list_members({ teamId: 'group-123' });
// members.members = [{ id, displayName, email, roles }]
SharePoint (3 tools)
| Tool | Description |
|---|---|
sharepoint_list_sites | List or search SharePoint sites |
sharepoint_search | Search content across SharePoint (files, list items, sites) |
sharepoint_list_items | List items in a SharePoint list |
Search Sites
const sites = await tools.sharepoint_list_sites({
query: 'Marketing',
maxResults: 10
});
Cross-Site Search
const results = await tools.sharepoint_search({
query: 'quarterly budget report',
entityTypes: ['driveItem', 'listItem'], // files and list items
maxResults: 10
});
Uses the Microsoft Search API to find content across all accessible SharePoint sites.
List Items
const items = await tools.sharepoint_list_items({
siteId: 'site-123',
listId: 'Tasks',
filter: "fields/Status eq 'Active'",
maxResults: 50
});
Microsoft Admin (13 tools)
Administrative tools for provisioning groups, sites, channels, users, and licenses. These require application permissions with admin consent.
Groups & Infrastructure
| Tool | Description | Requires Approval |
|---|---|---|
ms_admin_create_group | Create a Microsoft 365 Group (mailbox, calendar, SharePoint site, Planner) | Yes |
ms_admin_add_group_member | Add a member or owner to a group | No |
ms_admin_create_sharepoint_site | Create a SharePoint site (via group provisioning) | Yes |
ms_admin_create_teams_channel | Create a Teams channel in an existing team | No |
ms_admin_teamify_group | Enable Teams for an existing Microsoft 365 Group | Yes |
// Create a group
const group = await tools.ms_admin_create_group({
displayName: 'C-Suite Team',
mailNickname: 'csuite',
description: 'Executive leadership team',
owners: ['ceo@company.com'],
teamId: 'team_abc123' // optional: link to MeetLoyd team
});
// Includes: mailbox, calendar, SharePoint site, and Planner
// Add a member
await tools.ms_admin_add_group_member({
groupId: group.group.id,
userIdOrEmail: 'newmember@company.com',
asOwner: false
});
// Create a Teams channel
await tools.ms_admin_create_teams_channel({
groupId: group.group.id,
displayName: 'Project Alpha',
membershipType: 'standard' // standard, private, shared
});
User Management
| Tool | Description | Requires Approval |
|---|---|---|
ms_admin_create_user | Create a new user in Azure AD | Yes |
ms_admin_list_users | List/search directory users | No |
ms_admin_update_user | Update user properties | No |
ms_admin_delete_user | Delete a user (recoverable for 30 days) | Yes |
// Create user
const user = await tools.ms_admin_create_user({
displayName: 'New User',
mailNickname: 'newuser',
userPrincipalName: 'newuser@company.onmicrosoft.com',
password: 'temporary-password',
forceChangePasswordNextSignIn: true,
department: 'Engineering',
jobTitle: 'Software Engineer'
});
// List users
const users = await tools.ms_admin_list_users({
filter: "department eq 'Engineering'",
maxResults: 50
});
// Update user
await tools.ms_admin_update_user({
userId: 'user-123',
jobTitle: 'Senior Software Engineer',
department: 'Platform Engineering'
});
License Management
| Tool | Description | Requires Approval |
|---|---|---|
ms_admin_list_licenses | List available license SKUs | No |
ms_admin_assign_license | Assign a license to a user | Yes |
ms_admin_revoke_license | Remove a license from a user | Yes |
ms_admin_get_user_licenses | Get a user's assigned licenses | No |
// List available licenses
const licenses = await tools.ms_admin_list_licenses();
// licenses.licenses = [{ skuId, skuPartNumber, totalUnits, consumedUnits, availableUnits }]
// Assign a license
await tools.ms_admin_assign_license({
userId: 'user-123',
skuId: 'c7df2760-2c81-4ef7-b578-5b5392b571df' // Microsoft 365 E3
});
// Check user's licenses
const userLicenses = await tools.ms_admin_get_user_licenses({
userId: 'user-123'
});
// Revoke a license
await tools.ms_admin_revoke_license({
userId: 'user-123',
skuId: 'c7df2760-2c81-4ef7-b578-5b5392b571df'
});
Connecting
Authentication Model
Microsoft 365 tools use Azure AD client credentials flow (application permissions). The agent impersonates a Microsoft 365 user via their assigned email address.
Prerequisites
- Register an app in Azure AD Portal
- Add API permissions (application type) — see table below
- Create a client secret
- Grant admin consent for all permissions
- Store credentials in the MeetLoyd vault:
MS_TENANT_ID— Azure AD tenant IDMS_CLIENT_ID— Application (client) IDMS_CLIENT_SECRET— Client secret value
- Assign email — each agent must have a Microsoft 365 email configured
Required Permissions by Service
| Service | Permissions |
|---|---|
| Outlook | Mail.ReadWrite, Mail.Send |
| OneDrive | Files.ReadWrite.All |
| Calendar | Calendars.ReadWrite |
| Teams meetings | OnlineMeetings.ReadWrite.All |
| Teams messaging | ChannelMessage.Send, Team.ReadBasic.All |
| SharePoint | Sites.Read.All |
| Admin: Groups | Group.ReadWrite.All |
| Admin: Sites | Sites.ReadWrite.All |
| Admin: Channels | Channel.Create |
| Admin: Users | User.ReadWrite.All, Directory.ReadWrite.All |
| Admin: Licenses | Organization.Read.All |
Automatic Workspace Provisioning
When you start a team with Microsoft 365 connected, MeetLoyd can automatically create an M365 Group with a SharePoint site for the team. The document library gets standard folders (Reports, Working, Shared, Archive) and agents are added as group members.
- Azure AD app configured: M365 Group and SharePoint site created automatically during team first-start
- No credentials: A guided task is created for your admin to set up manually
Team bosses and lead agents become group owners, regular agents become members. Group members automatically get edit access to the SharePoint document library.
After provisioning, you can manage the workspace from the team's Workspace tab in the dashboard. See Team Workspace Provisioning for full details.
Files & Attachments Integration
Microsoft 365 tools work alongside MeetLoyd's file management system:
- Agents can read and upload files to OneDrive
- Agents can create blank or rich Office documents (Word, Excel, PowerPoint) directly in OneDrive
- Agents can generate professional slide decks, structured Word documents with tables, and multi-sheet Excel workbooks
- Agents can read and write Excel data for reporting and data management
- Agents can share files with team members
- For local file operations (security scanning, parsing, RAG), use MeetLoyd's built-in file management
Best Practices
1. Use Least Privilege
Only request the permissions your agents actually need:
// ✅ Good - only what's needed
permissions: ['Mail.Read', 'Calendars.Read']
// ❌ Bad - overly broad
permissions: ['Mail.ReadWrite.All', 'Sites.FullControl.All']
2. Assign Dedicated Agent Emails
Each agent should have its own Microsoft 365 mailbox for:
- Clear audit trail
- Isolated mailbox per agent role
- Easy revocation
3. Use Server-Side Filtering
// ✅ Good - server-side filter
await tools.outlook_list({
filter: "from/emailAddress/address eq 'support@company.com' and isRead eq false"
});
// ❌ Bad - fetching everything
await tools.outlook_list({ maxResults: 100 });
4. Use Named Tables for Excel
Create named tables before using excel_append — it enables structured data management:
// 1. Write headers + initial data
await tools.excel_write({
fileId: 'file-123',
range: 'A1:C2',
values: [['Name', 'Amount', 'Status'], ['Acme', '50000', 'Active']]
});
// 2. Create a named table
await tools.excel_create_table({
fileId: 'file-123',
range: 'A1:C2',
hasHeaders: true,
name: 'Deals'
});
// 3. Append rows as data comes in
await tools.excel_append({
fileId: 'file-123',
tableName: 'Deals',
values: [['Globex', '75000', 'Pending']]
});
Troubleshooting
"No Azure Credentials"
The tool returns a setupGuide array with steps. Check that MS_TENANT_ID, MS_CLIENT_ID, and MS_CLIENT_SECRET are stored in the vault.
"Insufficient Privileges"
- Check API permissions in Azure AD app registration
- Ensure admin consent was granted (application permissions require this)
- Verify the agent's email is a licensed Microsoft 365 account
"No Agent Email"
Each agent must have a Microsoft 365 email assigned in its settings page.
"Request Throttled"
Microsoft Graph has service-specific limits:
| Service | Limit |
|---|---|
| Outlook | 10,000 requests/10 minutes |
| OneDrive | 10,000 requests/10 minutes |
| Teams | 2,000 requests/minute |
Next: Explore Security Features for authentication and compliance.