CLI for Microsoft 365 MCP Server
The Microsoft 365 MCP Server allows programmatic interaction with Microsoft 365 lists by wrapping CLI for Microsoft 365 commands. You can:
Create a new list: Add a list to a specified site using the
list-addoperation with a title and site URLRetrieve list information: Get details about a specific list, optionally including permissions
List all lists: Fetch all lists within a specified site by providing the site URL
Remove a list: Delete a list from a site using the list title and site URL
Enables GitHub Copilot Agent to interact with Microsoft 365 services, allowing execution of Microsoft 365 CLI commands through the MCP server integration in VS Code.
Runs Microsoft 365 MCP server on Node.js runtime, enabling execution of CLI commands for Microsoft 365 services programmatically.
Utilizes TypeScript for implementing the Microsoft 365 MCP server, leveraging the MCP TypeScript SDK for development.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@CLI for Microsoft 365 MCP Serverlist my recent Teams messages and show the last 5 SharePoint sites"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
💡 Description
This MCP server allows the use of natural language to execute any CLI for Microsoft 365 commands. It may handle complex prompts that will be executed as a chain of CLI for Microsoft 365 commands that will try to fulfill the user's request. Thanks to this, you may manage many different areas of Microsoft 365, for example: Entra ID, OneDrive, OneNote, Outlook, Planner, Power Apps, Power Automate, Power Platform, SharePoint Embedded, SharePoint Online, Teams, Viva Engage, and many more...
For best results, use it with Claude Sonnet 4 or Claude Sonnet 3.7.
Related MCP server: Microsoft MCP
📦 Prerequisites
Node.js 20.x or higher
CLI for Microsoft 365 installed globally (
npm i -g @pnp/cli-microsoft365)
🚀 Installation & Usage
This MCP server uses the globally installed CLI for Microsoft 365 that you need to install globally using npm i -g @pnp/cli-microsoft365.
After you install the CLI for Microsoft 365 perform the initial setup by running the:
m365 setupFor more information, please follow the Log in to Microsoft 365
After you set up the CLI for Microsoft 365, please update its configuration using the following commands:
m365 cli config set --key prompt --value false
m365 cli config set --key output --value text
m365 cli config set --key helpMode --value fullThis will ensure that the MCP server will get as much information as possible from the CLI for Microsoft 365 when an error occurs or when a command is not executed properly.
The MCP server will not do any authentication for you. You will need to first authenticate using CLI for Microsoft 365 using m365 login command. Once you are authenticated, the MCP server will use the same authentication context when running any tool.
Lastly, install the MCP server on your preferred MCP client, referring to the instructions of the picked MCP host. Below, you may find guidance for VS Code.
Add to VS Code
There are multiple ways to add the MCP server to VS Code. The most common way is to:
Open the Command Palette (Ctrl+Shift+P or Cmd+Shift+P on macOS) and type
MCP: Add Server.Select
Command (stdio)as the server type.Enter the command to run the MCP server, which is:
npx -y @pnp/cli-microsoft365-mcp-server@latestName the server (e.g.,
CLI for Microsoft 365 MCP Server).
As a result, you should have the following configuration in your .vscode/mcp.json file:
{
"servers": {
"CLI for Microsoft 365 MCP Server": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@pnp/cli-microsoft365-mcp-server@latest"
]
}
}
}Now when you open the GitHub Copilot chat in VS Code, you should be able to select the CLI for Microsoft 365 MCP Server from the list of available MCP servers and start using it to manage Microsoft 365 using natural language. In the prompt specify that "Using CLI for Microsoft 365, I want you to..." and GitHub Copilot Agent will use the MCP server to execute your request.
Add to GitHub Copilot CLI
If you are using GitHub Copilot CLI, you may add the CLI for Microsoft 365 MCP server to Copilot by doing the following:
First of all start the Copilot CLI by running:
copilotUse the copilot mcp command to add the MCP server:
/mcp addThis will open up the MCP form where you need to fill in the following details:
Server name: basically whatever you like, but do not use space bar characters, e.g
cli-microsoft365-mcp-serverServer type: select
LocalCommand:
npxArguments:
"-y", "@pnp/cli-microsoft365-mcp-server@latest"Rest of the fields you may leave with default values.
After that click on Ctrl+S to save the MCP server and q to exit the MCP form.
Now you should be able to use the CLI for Microsoft 365 MCP server in GitHub Copilot CLI by specifying it in your prompt, e.g. "Using CLI for Microsoft 365, I want you to...".
Add to Claude
When using Claude Desktop you may add the MCP server by adding it manually to the Claude Desktop configuration.
Manually add to Claude Desktop configuration
In Claude Desktop, open Settings by clicking on the hamburger icon in the top left corner.
Select File > Settings (or press
Ctrl + ,)In the Developer tab, click Edit Config Note: If you don't see the Developer tab, you need to enable it first from Help > Enable Developer Mode.
This opens explorer, edit
claude_desktop_config.jsonin your favorite text editor. Add the following configuration to the file.
{
"mcpServers": {
"CLI-Microsoft365": {
"command": "npx",
"args": ["-y", "@pnp/cli-microsoft365-mcp-server@latest"]
}
}
}Exit Claude Desktop and restart it. Every time you make changes to the code or configuration, you need to restart Claude desktop for the changes to take effect.
Note: In Windows, Claude doesn't exit when you close the window, it runs in the background. You can find it in the system tray. Right-click on the icon and select Quit to exit the application completely.
All done! You should now be able to use the CLI-Microsoft365 MCP server in Claude Desktop.
Add to Cursor
When using Cursor you can add the MCP server by doing the following:
From the chat option pick the
Agent settingsoptionGo to
Tools & MCPtab and click onNew MCP serverModify the
mcp.jsonconfiguration as follows:
{
"mcpServers": {
"CLI for Microsoft 365 MCP Server": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@pnp/cli-microsoft365-mcp-server@latest"
]
}
}
}Save and enable the 'CLI for Microsoft 365 MCP Server' in the
Tools & MCPtab and wait for the tools to load.
📷 Use Cases
The below uses cases are only a few example how you may use this MCP server. It is capable of handling many different tasks, so feel free to experiment with it and basically manage all of Microsoft 365 using natural language.
Also you may check the CLI for Microsoft 365 wiki to find more scenarios how ClI for Microsoft 365 can be used to manage Microsoft 365.
Manage SharePoint Online
In the following example, the MCP server created a SharePoint list with new columns and populated it with a few test items.
prompt: "Add a new list to this site with title "awesome ducks". Then add new columns to that list including them in the default view. The first should be a text description columns and the second one should be a user column. Then add 3 items to this list with some funny jokes about docs added in the description column and adding my user in the user column. use emojis 🙂"

Manage Microsoft Teams
The following example shows how to create a new Microsoft Teams team and add a welcome post to the General channel.
prompt: "Create a new Team on Teams with name "Awesome Ducks" and in the General channel adda a welcome post"

Manage Power Platform solutions
In the example, the MCP server disables a Power Automate flow.
prompt: "can you check if I have HoursReportingReminder flow and if so disable it"

Manage Planner
In the following example, the MCP server creates a new Planner plan with sample buckets and tasks.
prompt: "can you create a new plan in planner to manage work for the awesome ducks. I need some sample buckets and tasks to get started"

🛠️ Tools
Tool | Description |
m365SearchCommands | Searches CLI for Microsoft 365 commands using fuzzy search based on a query string. This is more efficient than getting all commands as it returns only relevant matches. Use this tool first to find relevant commands. |
m365GetCommandDocs | Gets documentation for a specified CLI for Microsoft 365 command to be used by the Model Context Protocol to provide detailed information about the command along with examples, use cases, and option descriptions |
m365RunCommand | Runs a specified CLI for Microsoft 365 command to be used by the Model Context Protocol to execute the command and return the result and reason over the response |
m365GetBestPractices | Gets best practices for using CLI for Microsoft 365 in scripts, including guidance on authentication checking, error handling, output handling, and configuration |
🎓 Skills
This repo includes custom GitHub Copilot skills that teach the AI how to use CLI for Microsoft 365 effectively. Skills are automatically loaded by GitHub Copilot when relevant tasks are detected.
Skill | Description |
| Guides Copilot on running |
| Guides Copilot on writing PowerShell scripts that automate Microsoft 365 management using |
🏗️ How to build and run it locally
Before anything, first run npm install to install all dependencies.
Then, in order to build the project run:
npm run buildRunning MCP in VS Code from local build
It is also possible to run the MCP server in VS Code from your local build so that it may be used by GitHub Copilot Agent. First, start the CLI for Microsoft 365 MCP server using the command:
npm run startNow go to VS Code GitHub Copilot Agent mode click on the tools icon, and select Add more tools. Then select Add MCP server and then Command (stdio) and enter the following command:
node FULL_PATH_TO_YOUR_PROJECT/dist/index.jsClick Enter and name it however you like. It is recommended to add it to workspace scope for testing. After that, open up your .vscode/mcp.json file and modify it so pass the environment variables needed for auth.
{
"servers": {
"m365-mcp-server": {
"type": "stdio",
"command": "node",
"args": [
"FULL_PATH_TO_YOUR_PROJECT/dist/index.js" // e.g. C:/workspace/repo/microsoft-365-mcp-server/dist/index.js
]
}
}
}Running MCP from local build using the inspector (Debugging)
One of the ways to test the CLI for Microsoft 365 MCP server is by using the MCP Inspector. Mostly, this setup is used for debugging purposes and to test the MCP server locally. First, start the MCP server using the command:
npm run startNow, in order to run the inspector for your MCP server, you need run the following command in the repo root folder location:
npx @modelcontextprotocol/inspector node dist/index.jsAfter that, wait for the inspector to start and open the inspector in your browser. You should see the MCP server running, and you should be able to query the tools and execute them locally.
🔗 Resources
Available Tools
4 toolslist-addC
Creates list in the specified site
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Title of the list to add. | |
| webUrl | Yes | URL of the site where the list should be added. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states 'Creates' which implies a write/mutation operation, but doesn't disclose any behavioral traits like permissions needed, whether the operation is idempotent, what happens on failure, or rate limits. This leaves significant gaps for an agent to understand how to use it safely.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise at just 5 words, with no wasted words. It's front-loaded with the core action and resource. Every word earns its place in conveying the essential purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given this is a creation/mutation tool with no annotations and no output schema, the description is insufficiently complete. It doesn't explain what the tool returns, error conditions, or behavioral constraints. For a tool that modifies state, more context is needed for safe and effective use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds minimal semantic context beyond the schema. It mentions 'in the specified site' which relates to the webUrl parameter, but doesn't explain what constitutes a valid site URL or provide examples. With 100% schema description coverage, the baseline is 3, and the description doesn't significantly enhance parameter understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Creates') and resource ('list in the specified site'), making the purpose understandable. However, it doesn't distinguish this tool from its siblings (list-get, list-list, list-remove), which would require mentioning it's specifically for creation rather than retrieval or deletion.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It doesn't mention prerequisites, when not to use it, or reference sibling tools like list-get or list-remove for different operations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-getC
Gets information about the specific list
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Title of the list. | |
| webUrl | Yes | URL of the site where the list is located. | |
| withPermissions | No | Set if you want to return associated roles and permissions of the list. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states 'Gets information', suggesting a read-only operation, but doesn't cover critical aspects like authentication requirements, rate limits, error handling, or what specific information is returned (e.g., metadata, content). For a tool with parameters and no output schema, this leaves significant gaps in understanding its behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, clear sentence that directly states the tool's purpose without unnecessary words. It's front-loaded and efficient, though it could be slightly more informative (e.g., by hinting at sibling tools). There's no wasted verbiage, making it appropriately concise for a basic tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has 3 parameters, no annotations, and no output schema, the description is incomplete. It doesn't explain what 'information' is retrieved, how to interpret parameters like 'withPermissions', or any behavioral traits. For a read operation with multiple inputs and no structured output, more context is needed to guide effective use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage, fully documenting the three parameters (title, webUrl, withPermissions). The description adds no additional meaning beyond what the schema provides, such as explaining parameter relationships or usage context. With high schema coverage, the baseline score of 3 is appropriate, as the description doesn't compensate but also doesn't detract.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the tool 'Gets information about the specific list', which clearly indicates a read operation on a list resource. However, it doesn't differentiate from sibling tools like 'list-list' (likely for listing multiple lists) or 'list-add'/'list-remove' (for modifications), leaving the specific scope ambiguous. The purpose is understandable but lacks sibling distinction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance is provided on when to use this tool versus alternatives. The description implies it's for retrieving details of a specific list, but it doesn't clarify prerequisites (e.g., needing the list's title and webUrl), contrast with 'list-list' for broader queries, or mention any constraints. Usage is implied from the purpose but without actionable advice.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-listC
Gets all lists within the specified site
| Name | Required | Description | Default |
|---|---|---|---|
| webUrl | Yes | URL of the site where the lists to retrieve are located. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full burden for behavioral disclosure. It states it 'Gets all lists' but doesn't mention whether this is a read-only operation, if it requires specific permissions, what format the output takes, or if there are rate limits. This leaves significant gaps for a tool that presumably returns multiple items.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, clear sentence with no wasted words. It's appropriately sized for a simple tool and front-loads the essential information, making it highly efficient.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the lack of annotations and output schema, the description is incomplete. It doesn't explain what 'all lists' means in practice (e.g., pagination, filtering, or return format), which is crucial for a retrieval tool. The simplicity of the tool doesn't excuse these omissions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema description coverage is 100%, with the single parameter 'webUrl' well-documented in the schema. The description adds no additional parameter semantics beyond what's already in the schema, so it meets the baseline for adequate but unremarkable coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Gets') and resource ('all lists within the specified site'), making the tool's purpose understandable. However, it doesn't explicitly differentiate from sibling tools like list-get (which presumably retrieves a single list), so it doesn't reach the highest score.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives like list-get or list-add. It mentions the site scope but doesn't explain why one would choose this over other list-related tools, leaving the agent without contextual usage instructions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list-removeC
Removes the specified list
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | Title of the list to remove. | |
| webUrl | Yes | URL of the site where the list to remove is located. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries full burden but only states 'removes' without detailing behavioral traits. It doesn't disclose if this is destructive, requires permissions, has side effects, or what happens on success/failure, which is inadequate for a mutation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, clear sentence with no wasted words, making it highly concise and front-loaded. It efficiently conveys the core action without unnecessary elaboration.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive tool with no annotations and no output schema, the description is incomplete. It lacks details on behavior, return values, error handling, or context compared to siblings, failing to compensate for the missing structured information.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with descriptions for 'title' and 'webUrl' parameters. The tool description adds no additional meaning beyond the schema, such as format examples or constraints, so it meets the baseline but doesn't enhance understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states the action ('removes') and resource ('the specified list'), which clarifies the tool's basic purpose. However, it's vague about what 'removes' entails (e.g., deletion, archiving) and doesn't differentiate from siblings like 'list-add' or 'list-get' beyond the verb, missing specificity about scope or effects.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided on when to use this tool versus alternatives. It doesn't mention prerequisites, exclusions, or compare to sibling tools like 'list-list' for listing or 'list-get' for retrieval, leaving the agent without context for selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
4 tool updates
v1.0.0- First observed
list-add - First observed
list-get - First observed
list-list - First observed
list-remove
TDQS
Each tool has a clearly distinct purpose targeting different CRUD operations on lists: create, retrieve specific, retrieve all, and delete. The descriptions explicitly differentiate them with no overlap or ambiguity.
All tools follow a perfect and consistent 'list-verb' pattern (list-add, list-get, list-list, list-remove) using hyphens and clear action verbs. This makes the naming highly predictable and readable.
With 4 tools, this server is well-scoped for managing lists in Microsoft 365 sites. Each tool earns its place by covering essential CRUD operations without bloat or missing core functionality.
The tool set provides complete CRUD/lifecycle coverage for lists: create (list-add), read specific (list-get), read all (list-list), and delete (list-remove). There are no obvious gaps for this focused domain.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Official Microsoft MCP Server to query Microsoft Entra data using natural language
MCP server for generating rough-draft project plans from natural-language prompts.
MCP server for AI dialogue using various LLM models via AceDataCloud
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceLokka ia an MCP server for the Microsoft Graph API and can be used to query and update all resources in your Microsoft 365 tenant. This MCP server supports all Microsoft Graph APIs including update operations (limited by the permissions you grant to the app).293MIT
- FlicenseCqualityFmaintenanceA powerful MCP server that enables AI assistants to interact with Microsoft Graph API for managing Outlook emails, Calendar events, OneDrive files, and Contacts through natural language commands.3556-
- AlicenseNot gradedqualityAmaintenanceA production-ready MCP server that provides secure, delegated access to Microsoft 365 services including Email, SharePoint, OneDrive, and Calendar. It enables AI models to search messages, browse files, manage calendar events, and parse document contents using OAuth 2.1 authentication.MIT
- AlicenseCqualityNot gradedmaintenanceAn MCP server that enables interaction with Microsoft 365 services like Outlook, OneDrive, Teams, and SharePoint via the Microsoft Graph API. It supports comprehensive operations including email management, file access, and organizational collaboration for personal and work accounts.78-
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/pnp/cli-microsoft365-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server