Microsoft 365 Copilot Plugins - How They Work and When to Build One
Most organisations we work with have the same question once they've rolled out Microsoft 365 Copilot - "This is great, but can it talk to our own systems?" The answer is yes, through plugins. And honestly, the plugin model has come a long way from the early days when it felt like you needed a PhD in YAML manifests to get anything working.
Plugins let declarative agents in Microsoft 365 Copilot interact with your own MCP servers or REST APIs. That means users can ask Copilot natural language questions and have it query, create, update, or delete data in your own backend systems. If your API can do it, Copilot can trigger it through a plugin.
We've been building these for clients across a few different industries now, and I wanted to share what we've learned about how they work, what the gotchas are, and where the real value sits.
The Two Flavours - MCP Server vs REST API
Microsoft gives you two paths for plugin development. You can connect Copilot to an MCP (Model Context Protocol) server, or you can connect it to a standard REST API with an OpenAPI description. Both get you to the same place - Copilot understanding what your backend can do and calling it when a user prompt matches.
The MCP server approach uses a tool-based model. You define tools (like get-budgets or charge-budget) and Copilot calls them via JSON-RPC style requests. The REST API approach is more traditional - you expose OpenAPI-described endpoints and Copilot maps prompts to HTTP verbs.
From a practical standpoint, if you already have a well-documented REST API, the REST plugin path is faster to get running. If you're building something new or want tighter control over the tool interface, MCP servers give you more flexibility.
How a Plugin Actually Executes
Let me walk through what happens when a user types something like "How much is left in the Fourth Coffee lobby renovation budget?" into a declarative agent that has a budget plugin installed.
First, Copilot looks at the installed plugins and their manifests. Each manifest describes what the plugin can do - the tools or API endpoints, their parameters, and what they return. Copilot matches the user's prompt against these descriptions and picks the best fit.
Then something important happens - Copilot asks the user for permission before sending any data to the plugin. This is a security feature that trips up people during demos but makes complete sense in production. The user confirms they're happy for their data to go to this external service.
After confirmation, if the plugin needs authentication (and most production ones do), the token store handles the auth flow. This might mean fetching an OAuth token or API key. If the user hasn't signed in yet, Copilot prompts them.
Finally, Copilot sends the request to your MCP server or API, gets the response back, and generates a conversational answer. The user sees something like "The available funds left in the Fourth Coffee lobby renovation budget are $5,000" rather than raw JSON.
The whole thing takes a few seconds end-to-end, which is honestly impressive considering the number of moving parts.
The Confirmation Model
This is worth understanding because it affects user experience quite a bit. Copilot has a built-in confirmation system that works differently depending on whether your plugin reads or writes data.
The first time a user interacts with any plugin, Copilot asks for permission. After that initial confirmation, read-only operations (GET requests, query tools) don't prompt again. But operations that modify data - creating, updating, deleting - will ask for confirmation each time by default.
You can override these defaults in your plugin manifest, which is useful. We've had situations where a client wanted every single call confirmed for compliance reasons, and other situations where the confirmation prompts were annoying enough that we relaxed them for low-risk write operations.
The key takeaway is to think about this during design, not after deployment. Your users will notice if every second action requires a click-through.
Making Copilot Actually Pick Your Plugin
Here's where a lot of teams stumble. You build a perfectly functional plugin, deploy it, and then find that Copilot ignores it half the time. The problem is almost always in how you've described the plugin.
The Copilot orchestrator decides which plugin to call based on the descriptions in your manifest - the plugin description, the operation/tool descriptions, and the parameter descriptions. If these are vague, Copilot can't confidently match user prompts to your plugin.
I've seen manifests where the plugin description was literally "Budget operations" with no further context. Compare that to "Query, create, and manage departmental budgets including expense tracking, fund allocation, and balance inquiries across organisational units." The second one gives Copilot much more to work with.
For REST API plugins, the OpenAPI description is what Copilot reads. Microsoft has specific guidance on how to write effective OpenAPI documents for Copilot, and I'd strongly recommend reading it before you write a single line of plugin code.
For MCP server plugins, the tool names and descriptions serve the same purpose. Be specific. Be descriptive. Don't abbreviate.
Adaptive Cards for Better Responses
By default, Copilot generates plain text conversational responses from your API data. That works fine for simple queries, but if you're returning structured data - a list of budget items with amounts, dates, and categories - a text paragraph isn't the best presentation.
Plugins can include Adaptive Card templates that Copilot uses to render structured responses. Think of it like providing a UI template for your data. When done well, this makes the experience feel much more polished than a wall of text.
We usually recommend starting without Adaptive Cards to get the functional flow right, then adding them once the plugin is working reliably. Trying to debug card rendering issues and API integration issues at the same time is a recipe for frustration.
What We've Seen Work in Practice
Across the plugin projects we've delivered, a few patterns stand out as particularly high-value.
Internal knowledge lookups are probably the most common. Companies with internal policy databases, pricing sheets, or technical documentation that staff need to query frequently. Instead of searching through SharePoint or a wiki, they ask Copilot and the plugin fetches the answer from a structured API.
Approval workflows work surprisingly well. "Approve the leave request from Sarah for next Monday" triggers a plugin that calls the HR system's API. The confirmation prompt actually helps here - it acts as a natural "are you sure?" step.
Financial reporting queries are another sweet spot. "What were our Q1 expenses for the Sydney office?" hitting a finance API and returning numbers with an Adaptive Card showing a breakdown table. Executives love this one.
The pattern that works less well, honestly, is anything requiring complex multi-step transactions. Copilot can chain a couple of API calls together, but if you need to query one system, transform the data, then write to another system - you're better off building that logic into your API and exposing a single endpoint.
The Authentication Question
Authentication deserves its own section because it's where most of the complexity lives. Your plugin can support OAuth 2.0, API keys, or no authentication (for internal-only scenarios).
For anything customer-facing, you want OAuth. This means setting up an app registration in Microsoft Entra, configuring the right scopes, and handling token refresh. It's not trivial, but it's well-documented and once it's done, it just works.
API keys are simpler but less secure - they're better suited for internal tools or development environments.
The gotcha we hit most often is scope configuration. If your API requires specific permissions, those need to be correctly mapped in the plugin manifest and the Entra app registration. Mismatched scopes result in silent failures that are genuinely painful to debug.
Getting Started
If you're thinking about building a Copilot plugin, here's my honest advice on where to start.
First, pick one specific use case. Don't try to plugin-ify your entire backend. Find the API endpoint or set of tools that would save the most time and build a plugin around just that.
Second, get your descriptions right from day one. The manifest descriptions are the single biggest factor in whether your plugin gets called reliably.
Third, test with real users early. The way people naturally phrase questions often differs from what you'd expect, and you'll need to iterate on descriptions based on real usage patterns.
Microsoft's official plugin documentation has everything you need for the technical implementation. The harder part is figuring out the right use case and the right descriptions.
Where Team 400 Fits
We've been building Microsoft 365 Copilot extensions since the extensibility model first launched, and plugins are the area where we see the most demand right now. If you've got an existing API that your team queries manually, or internal tools that could benefit from a conversational interface, a plugin is probably the fastest path to value.
We offer Copilot Studio consulting for organisations looking to build and deploy these, and our broader AI agent development practice covers the full spectrum from plugin design through to production deployment.
If you're not sure whether a plugin is the right approach or whether a full custom agent makes more sense, get in touch and we can talk through your specific situation. The answer depends on your existing systems, your users, and what you're actually trying to achieve.