Connect Microsoft 365 to AI Agents: Search, Messaging, and Tasks
Give your AI agent Microsoft 365 tools.
Connect Microsoft 365 to your AI agents via Truto's unified tools layer. Bypass Microsoft Graph's complex OData syntax and opaque IDs to build autonomous Teams, Planner, and SharePoint workflows.
In this guide
- 01Understand Microsoft Graph API Quirks
- 02Fetch Microsoft 365 Tools
- 03Bind Tools to the LLM
- 04Execute the Agent Loop
- 05Handle Rate Limits and Errors
The guide
Learn how to connect Microsoft 365 to AI agents using Truto's tools endpoint to automate Teams messaging, Planner tasks, and SharePoint search.
You want to connect Microsoft 365 to an AI agent so your system can autonomously search SharePoint documents, orchestrate Planner tasks, and dispatch messages across Microsoft Teams based on historical organizational context. Here is exactly how to do it using Truto's /tools endpoint and SDK, bypassing the need to build and maintain a custom Microsoft Graph integration from scratch.
Giving a Large Language Model (LLM) read and write access to your Microsoft 365 tenant is an engineering challenge that typically ends in endless edge cases. You either spend sprints trying to normalize the massive surface area of the Microsoft Graph API into schemas an LLM can understand, or you use a managed infrastructure layer that handles the boilerplate for you. If your team uses ChatGPT, check out our guide on connecting Microsoft 365 to ChatGPT, or if you are building on Anthropic's models, read our guide on connecting Microsoft 365 to Claude. For developers building custom autonomous workflows, you need a programmatic way to fetch these tools and bind them directly to your agent framework.
This guide breaks down exactly how to fetch AI-ready tools for Microsoft 365, bind them natively to an LLM using LangChain (or any framework like LangGraph, CrewAI, or the Vercel AI SDK), and execute complex productivity workflows. For a deeper look at the architecture behind this approach, refer to our research on architecting AI agents and the SaaS integration bottleneck.
The Engineering Reality of the Microsoft Graph API
Direct API tools - mapping one tool to one raw Microsoft Graph endpoint - look convenient in a sandbox, but they push vendor-specific quirks straight into the LLM's context window. If you hardcode these interactions into your agent, you will spend your time writing defensive integration code instead of improving your model's reasoning logic.
The Microsoft 365 API (Microsoft Graph) introduces several specific integration challenges that break standard REST assumptions and consistently cause AI agents to fail.
The OData Query Syntax Trap
Microsoft Graph relies heavily on the OData protocol for shaping responses. Standard LLMs are trained to expect straightforward REST payloads, but the Graph API routinely requires $select, $expand, and $filter query parameters to return useful data. For example, if an agent requests a user's profile, the default Graph response omits critical relationships like the user's manager or their assigned licenses. To get that, the API requires a specific ?$expand=manager query string.
When an LLM is given raw Graph API access, it has to remember the exact syntax and supported $expand properties for every single resource. It frequently hallucinates OData operators or attempts to expand properties that Microsoft does not support, resulting in HTTP 400 Bad Request errors that crash the agent loop.
Deeply Nested Resource Routing and Opaque IDs
Navigating Microsoft 365 data programmatically requires stringing together deeply nested routes using opaque identifiers. For an agent to read a file from a SharePoint site, it cannot simply pass a file name. It must:
- Find the
site_id. - List drives in that site to find the
drive_id. - Search the drive to find the
item_id. - Request the content using
/sites/{site_id}/drives/{drive_id}/items/{item_id}/content.
These IDs are long, base64-encoded, or GUID strings. If the LLM misses a step in this chain or attempts to guess an ID based on a human-readable name, the API call fails.
Unpredictable Permission Scopes
Microsoft Graph's consent framework is notoriously granular. An endpoint might require Group.ReadWrite.All, but if the agent is operating under a token scoped only to User.Read, the call will fail with a 403 Forbidden error. Furthermore, some operations require Application permissions while others require Delegated permissions. Exposing the raw API means your agent must constantly navigate authorization contexts it cannot resolve on its own.
A unified tool layer collapses these Microsoft 365 quirks behind a clean schema. Your agent sees stable functions with deterministic JSON schemas, meaning invalid arguments are rejected before they ever hit the Graph API. This drastically shrinks the attack surface for hallucinations.
Microsoft 365 Hero Tools for AI Agents
Truto provides all the resources defined on an integration as tools for your LLM frameworks to use. Rather than forcing the LLM to learn Microsoft Graph, you provide it with discrete, purpose-built functions.
Here are the highest-leverage tools available for orchestrating Microsoft 365 workflows.
list_all_microsoft_365_search
This tool executes a Microsoft Search query across the tenant's content, returning matching search hits. It abstracts away the complex POST body required by the Graph search endpoint, allowing the agent to find documents, messages, and list items using natural language queries.
"Find the Q3 financial planning spreadsheet in SharePoint and return the exact document ID so I can download it."
microsoft_365_drive_item_download_download
Instead of forcing the LLM to parse Microsoft's unique download URLs or handle raw byte arrays directly in the chat context, this tool safely retrieves the raw binary content stream of a file from a SharePoint site or OneDrive. It is critical for feeding documents into RAG (Retrieval-Augmented Generation) pipelines or summarization agents.
"Download the contents of the onboarding guide document located in the HR drive so I can summarize the new remote work policy."
create_a_microsoft_365_chat_message
This tool allows the agent to dispatch a new message into a specific Microsoft Teams chat. It handles the specific formatting requirements of the Graph chatMessage resource schema, ensuring the LLM doesn't break the payload structure when adding mentions or HTML formatting.
"Send a message to the engineering team chat letting them know that the production deployment has successfully finished."
list_all_microsoft_365_tasks
This tool retrieves Planner tasks belonging to a specific plan. Because Microsoft Planner data is highly relational, this tool normalizes the response so the agent can easily see task statuses, assignees, and due dates without having to manually $expand multiple OData paths.
"List all incomplete tasks in the Q4 Marketing Launch plan and tell me which ones are assigned to Sarah."
get_single_microsoft_365_user_by_id
This tool retrieves a comprehensive profile of a Microsoft Entra user. It surfaces detailed attributes - such as job title, department, business phones, and manager hierarchies - that are typically hidden behind Graph API expansion flags.
"Look up the profile for the user ID 8a9b2c-1234 and tell me who their direct manager is."
create_a_microsoft_365_bucket
In Microsoft Planner, a "bucket" is a column or phase within a plan. This tool allows an autonomous project management agent to dynamically create new organizational structures within a team's workflow.
"Create a new Planner bucket called 'Blocked by QA' in the current sprint plan."
For a complete list of all available Microsoft 365 tools and their exact JSON schemas, review the Microsoft 365 integration page.
Workflows in Action
When you equip an LLM with these tools, it stops acting as a simple chat interface and becomes an autonomous operator capable of handling multi-step administrative burdens. Here is how specific workflows execute in production.
Workflow 1: The Autonomous Project Manager
Persona: Technical Project Manager tracking sprint deliverables across Teams and Planner.
"Check the 'Website Redesign' plan for any tasks that are past due. If you find any, ping the assigned user in the 'Design Sync' Teams chat to ask for an update."
- The agent calls
list_all_microsoft_365_me_plansto locate the ID for the "Website Redesign" plan. - It calls
list_all_microsoft_365_taskspassing theplan_idto retrieve all tasks. - The agent filters the results in memory to identify tasks where the due date is in the past and the status is incomplete.
- It identifies the assignee IDs and calls
get_single_microsoft_365_user_by_idto get their display names. - It calls
list_all_microsoft_365_chatsto locate the ID for the "Design Sync" chat. - Finally, it calls
create_a_microsoft_365_chat_messageto dispatch a formatted message tagging the specific users and referencing their late tasks.
Output: The LLM independently bridges two separate Microsoft 365 products (Planner and Teams), enforcing project management hygiene without requiring human oversight.
Workflow 2: Contextual E-Discovery and Briefing
Persona: Operations Lead needing immediate context on organizational assets.
"Search SharePoint for the latest 'Vendor Security Policy'. Download the document, summarize the primary compliance requirements, and send that summary directly to me in Teams."
- The agent calls
list_all_microsoft_365_searchwith the query "Vendor Security Policy" to locate the document across the tenant. - It parses the search hits to extract the
site_id,drive_id, anditem_idof the most relevant result. - It calls
microsoft_365_drive_item_download_downloadto retrieve the raw file content. - The LLM processes the downloaded text in its context window to generate a summary.
- It calls
list_all_microsoft_365_chatsto find its direct message thread with the requesting user. - It calls
create_a_microsoft_365_chat_messageto deliver the summary.
Output: The user receives a concise briefing in their Teams client based on a document they didn't have to manually hunt down or read.
Building Multi-Step Workflows
To build these workflows, you need to bind Truto's tools to your LLM and manage the execution loop. Because Truto's /tools endpoint returns standardized schemas, this approach works with any modern framework - LangChain, LangGraph, CrewAI, or the Vercel AI SDK.
Here is how to architect the integration using LangChain.js and the TrutoToolManager.
Architecture Flow
sequenceDiagram
participant App as Your Agent App
participant LLM as LLM (OpenAI/Anthropic)
participant Truto as Truto API
participant Graph as Microsoft Graph API
App->>Truto: GET /integrated-account/{id}/tools
Truto-->>App: Return Microsoft 365 tool schemas
App->>LLM: .bindTools(schemas) + Prompt
LLM-->>App: tool_call: list_all_microsoft_365_search
App->>Truto: Execute tool via Proxy API
Truto->>Graph: POST /search/query (OData)
Graph-->>Truto: Return Search Results
Truto-->>App: Standardized JSON output
App->>LLM: Submit tool output
LLM-->>App: Final natural language responseBinding the Tools
First, you fetch the tools for the specific Microsoft 365 integrated account and bind them to your model.
import { ChatOpenAI } from "@langchain/openai";
import { TrutoToolManager } from "truto-langchainjs-toolset";
// Initialize the manager with your Truto API key
const trutoManager = new TrutoToolManager({
apiKey: process.env.TRUTO_API_KEY
});
// Fetch the Microsoft 365 tools for a specific tenant's integrated account
const accountId = "YOUR_MICROSOFT_365_INTEGRATED_ACCOUNT_ID";
const tools = await trutoManager.getTools(accountId);
// Initialize your LLM and bind the tools
const llm = new ChatOpenAI({
modelName: "gpt-4o",
temperature: 0,
});
const llmWithTools = llm.bindTools(tools);Handling Execution and Rate Limits (HTTP 429)
The Microsoft Graph API aggressively rate-limits requests to protect tenant stability. It is crucial to understand that Truto does not retry, throttle, or apply backoff on rate limit errors. Truto's philosophy is to give developers full visibility and control over the integration lifecycle.
When Microsoft Graph returns an HTTP 429 Too Many Requests error, Truto passes that error directly back to the caller. Truto normalizes the upstream rate limit information into standardized HTTP headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per the IETF specification. Your agent framework is responsible for inspecting these headers, sleeping for the required duration, and retrying the tool call.
Here is how you handle the agent loop and gracefully manage rate limits:
import { HumanMessage } from "@langchain/core/messages";
async function runAgentLoop(prompt: string) {
const messages = [new HumanMessage(prompt)];
while (true) {
const response = await llmWithTools.invoke(messages);
messages.push(response);
// If the LLM didn't call a tool, we are done
if (!response.tool_calls || response.tool_calls.length === 0) {
console.log("Agent finished:", response.content);
break;
}
// Execute each tool call requested by the LLM
for (const toolCall of response.tool_calls) {
const tool = tools.find(t => t.name === toolCall.name);
if (tool) {
try {
console.log(`Executing ${tool.name}...`);
const toolResult = await tool.invoke(toolCall.args);
messages.push(toolResult);
} catch (error) {
// Explicitly handle Truto passing back the upstream 429 rate limit
if (error.response && error.response.status === 429) {
const resetSeconds = error.response.headers.get('ratelimit-reset');
console.warn(`Rate limited by Microsoft Graph. Waiting ${resetSeconds} seconds...`);
// Sleep for the required duration before allowing the loop to retry
await new Promise(resolve => setTimeout(resolve, parseInt(resetSeconds) * 1000));
// Inform the LLM of the delay so it can retry the specific tool call
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify({ error: `Rate limited. Paused for ${resetSeconds}s. Please retry.` })
});
} else {
// Handle generic errors (e.g., 403 Forbidden or 404 Not Found)
messages.push({
role: "tool",
tool_call_id: toolCall.id,
content: JSON.stringify({ error: error.message })
});
}
}
}
}
}
}
// Execute the autonomous workflow
await runAgentLoop("Find the Q3 planning doc and summarize it in the marketing channel");In this architecture, the LLM maintains awareness of the execution state. If a tool fails due to a rate limit or a missing permission, the error is appended to the message history. The LLM can then dynamically decide to retry the call, attempt a different tool, or alert the user that it lacks the necessary access.
Moving from Prototype to Production
Building an AI agent that talks to Microsoft 365 is easy when you hardcode a single token and a single endpoint for a prototype. It becomes an engineering nightmare when you deploy it to production and have to handle multi-tenant OAuth lifecycles, Microsoft Graph's deeply nested identifiers, and strict schema validation across thousands of enterprise users.
By leveraging Truto's /tools endpoint, you delegate the entire API normalization layer. Your agent interacts with a clean, deterministic schema, and your engineering team stays focused on improving the model's logic, not debugging OData syntax errors.
FAQ
- How does Truto handle Microsoft 365 rate limits for AI agents?
- Truto does not retry, throttle, or absorb rate limits. When Microsoft Graph returns an HTTP 429, Truto passes that error to your application and normalizes the rate limit headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset) per the IETF specification. Your agent framework is responsible for handling the backoff.
- Yes. Truto provides specific tools like `microsoft_365_drive_item_download_download` that return the raw binary content stream of a file, allowing your AI agent to download and process documents for RAG pipelines or summarization.
- Which agent frameworks work with Truto's Microsoft 365 tools?
- Truto's tools endpoint is framework-agnostic. Because it returns standard JSON schemas for the tools, it integrates natively with LangChain, LangGraph, CrewAI, Vercel AI SDK, and any other framework that supports OpenAI-style tool calling.