| name | microsoft-365-integration |
| description | Integrate with Microsoft 365 using the Microsoft Graph API. Covers Outlook mail, calendar, Teams, OneDrive, SharePoint, and Excel automation for building AI-powered productivity workflows. |
| license | Apache 2.0 |
| tags | ["microsoft-365","graph-api","outlook","teams","sharepoint","onedrive","office","enterprise"] |
| difficulty | intermediate |
| time_to_master | 8-14 weeks |
| version | 1.0.0 |
Microsoft 365 Integration
Overview
Microsoft 365 powers 400M+ paid seats globally. The Microsoft Graph API provides unified access to Outlook mail, Calendar, Teams, OneDrive, SharePoint, Excel, and more — all through a single REST endpoint. AI agents with Graph API access can manage email, schedule meetings, search documents, post to Teams channels, and automate office workflows.
When to Use This Skill
- Building MCP servers that manage Outlook email and calendar
- Automating Teams messages, channel management, and meeting scheduling
- Implementing document management with OneDrive and SharePoint
- Creating AI-powered email triage and response workflows
- Building enterprise search across Microsoft 365 content
Core Concepts
Microsoft Graph API Structure
https://graph.microsoft.com/v1.0/
├── /me/ (Current user)
│ ├── /messages (Outlook mail)
│ ├── /calendar/events (Calendar)
│ ├── /drive/root (OneDrive files)
│ ├── /joinedTeams (Teams)
│ └── /contacts (People)
├── /users/{id}/ (Specific user)
├── /groups/{id}/ (Groups/Teams)
├── /sites/{id}/ (SharePoint)
└── /teams/{id}/channels (Teams channels)
Authentication: Azure AD OAuth 2.0
| Flow | Use Case | Scopes |
|---|
| Authorization Code | User-interactive apps | Delegated permissions |
| Client Credentials | Daemon/service apps | Application permissions |
| On-Behalf-Of | API-to-API delegation | Delegated via middleware |
Common Permissions
| Operation | Permission (Delegated) | Permission (Application) |
|---|
| Read mail | Mail.Read | Mail.Read |
| Send mail | Mail.Send | Mail.Send |
| Read calendar | Calendars.Read | Calendars.Read |
| Create events | Calendars.ReadWrite | Calendars.ReadWrite |
| Read files | Files.Read | Files.Read.All |
| Post to Teams | ChannelMessage.Send | ChannelMessage.Send |
Implementation Guide
Email Management
import { Client } from "@microsoft/microsoft-graph-client";
const graphClient = Client.init({
authProvider: (done) => done(null, accessToken),
});
const messages = await graphClient
.api("/me/messages")
.select("subject,from,receivedDateTime,bodyPreview,isRead")
.filter("isRead eq false")
.orderby("receivedDateTime desc")
.top(20)
.get();
await graphClient
.api("/me/sendMail")
.post({
message: {
subject: "Q2 Pipeline Review",
body: {
contentType: "HTML",
content: "<p>Please review the attached pipeline summary.</p>",
},
toRecipients: [
{ emailAddress: { address: "manager@company.com" } },
],
},
});
const searchResults = await graphClient
.api("/me/messages")
.()
.()
.()
.();
Calendar Operations
const events = await graphClient
.api("/me/calendarView")
.query({
startDateTime: new Date().toISOString(),
endDateTime: new Date(Date.now() + 7 * 86400000).toISOString(),
})
.select("subject,start,end,location,attendees,isOnlineMeeting")
.orderby("start/dateTime")
.get();
const newEvent = await graphClient
.api("/me/events")
.post({
subject: "Design Review",
start: { dateTime: "2026-04-01T14:00:00", timeZone: "America/New_York" },
end: { dateTime: "2026-04-01T15:00:00", timeZone: "America/New_York" },
attendees: [
{
emailAddress: { address: "colleague@company.com", name: "Jane Doe" },
type: "required",
},
],
isOnlineMeeting: ,
: ,
});
availability = graphClient
.()
.({
: [
{ : { : }, : },
],
: {
: [{
: { : , : },
: { : , : },
}],
},
: ,
});
Teams Integration
await graphClient
.api(`/teams/${teamId}/channels/${channelId}/messages`)
.post({
body: {
contentType: "html",
content: "<h3>Daily Pipeline Update</h3><p>3 deals moved to negotiation stage today.</p>",
},
});
const messages = await graphClient
.api(`/me/chats/${chatId}/messages`)
.top(50)
.get();
Microsoft 365 MCP Server
server.tool(
"search_emails",
"Search Outlook emails by subject, sender, or content",
{
query: z.string().describe("Search terms"),
folder: z.enum(["inbox", "sent", "drafts", "all"]).default("inbox"),
unreadOnly: z.boolean().default(false),
days: z.number().default(7),
},
async ({ query, folder, unreadOnly, days }) => {
let filter = `receivedDateTime ge ${daysAgo(days)}`;
if (unreadOnly) filter += " and isRead eq false";
const messages = await graphClient
.api("/me/messages")
.search(`"${query}"`)
.filter(filter)
.select("subject,from,receivedDateTime,bodyPreview,isRead")
.top(15)
.get();
return {
content: [{
type: "text",
text: messages.value.(
+
).(),
}],
};
}
);
server.(
,
,
{
: z.().(),
},
({ days }) => {
events = graphClient
.()
.({
: ().(),
: (.() + days * ).(),
})
.()
.()
.();
{
: [{
: ,
: events..(
+
+
+
(e. ? : )
).(),
}],
};
}
);
Best Practices
- Use delegated permissions when acting on behalf of a user; application permissions for daemons
- Request minimal scopes — only ask for permissions the app actually needs
- Use $select to limit fields — reduces payload size and improves performance
- Implement delta queries for incremental sync instead of full re-fetch
- Handle throttling — respect
Retry-After headers on 429 responses
- Use batch requests — combine up to 20 requests in a single batch call
Resources
Changelog
| Version | Date | Changes |
|---|
| 1.0.0 | 2026-03-31 | Initial documentation |