Adding UI to Microsoft 365 Copilot with MCP Apps - What We Have Learned
Until recently, extending Microsoft 365 Copilot meant building text-in, text-out experiences. You wired up an action, the user asked something, Copilot replied in chat. Fine for simple lookups, not great for anything that needed structured display or interaction.
The MCP apps with UI capability changes that. You can now build a Copilot extension that surfaces actual UI - cards, forms, embedded panels - inside the chat experience. It's the bridge between MCP's clean tooling model and the richer UI that business users actually expect.
We've been building Copilot extensions for Australian clients for over a year now. The UI story is a real step forward, but it's also got some rough edges that the docs don't dwell on. Here's the practical view from the field.
What this actually is
MCP (Model Context Protocol) is the open standard Anthropic launched that has now been adopted across the AI ecosystem. It's a way for AI assistants to talk to external tools, with a clean separation between the model and the tool implementation.
Microsoft 365 Copilot has supported MCP as a way to connect to data sources for a while. What's new is that MCP servers can now also return UI elements - structured cards or embedded apps that Copilot renders inside the chat thread, rather than just text responses.
In practice this means you can build an MCP server that, when invoked, returns:
A response card that shows structured data with formatting, icons, and actions.
An embedded full-app surface that takes over part of the Copilot pane for richer interaction (think a mini-app inside Copilot).
A form for collecting user input before continuing the conversation.
It's all anchored on Adaptive Cards (Microsoft's existing card framework) which is good and bad. Good because it's a known format that works across Teams and Outlook. Bad because Adaptive Cards have always been a bit awkward to design for and the constraints are real.
Why this matters for Copilot extensions
Text-only Copilot extensions hit a ceiling fast. Anything beyond simple lookups gets clunky. Imagine asking Copilot "show me my open service tickets" and getting back a wall of text. Now imagine getting a card with each ticket as a row, status indicators, action buttons to acknowledge or reassign. The second experience is the one users actually want.
For Australian clients building internal copilots, this changes the calculation on whether Copilot is the right surface or whether they need to build something custom. We've had several conversations recently where a client was about to commit to building a separate internal web app because Copilot couldn't do what they needed. With UI in MCP apps, Copilot can now do more of those things and the case for a separate app gets weaker.
The other angle: this opens up Copilot as a delivery channel for tools that already exist. If you have an internal system that's already got an API, you can wrap it as an MCP server with a basic UI and ship it as a Copilot extension. The user doesn't need to learn a new tool, they just ask Copilot.
We do a lot of this kind of integration work as part of our Microsoft 365 Copilot consulting and increasingly the answer to "should we build this in Copilot or as a separate app?" is shifting toward Copilot.
What it actually takes to build
The build experience is improving but it's not yet smooth. Here's the rough shape:
You need an MCP server. Node.js or .NET both work. Microsoft has SDKs for both. The server exposes the tools (functions) that Copilot can call, and now also defines the UI elements those tools can return.
You need to declare the MCP app in your Copilot extensibility manifest, including the UI capabilities. The manifest tells Copilot what cards and surfaces your app can render, which is part of the safety boundary - Copilot won't let the app render arbitrary UI, only what's been declared.
You build the cards in Adaptive Cards format. Microsoft has a designer at adaptivecards.io that helps but it's not as polished as you'd expect for a feature being pushed this hard.
You handle the round-tripping. When the user interacts with a card (clicks a button, submits a form), that comes back to your MCP server as a tool invocation. You process it and return the next state.
It's all sensible, but the cycle time during development is rough. Test the change, deploy, refresh Copilot, try it. Iterate. The tooling for local development against Copilot is improving but not as fluid as building a regular web app yet.
What works well
A few things have been good in our actual builds:
Authentication is handled cleanly. MCP apps in the Microsoft 365 ecosystem use Entra ID and the auth flow is largely managed for you. You're not building OAuth flows. This is one of the better aspects of the experience.
The cards render consistently across Copilot in Teams, Word, Excel, and the standalone Copilot app. Once you build a card, it shows up the same everywhere, which has been a long-standing pain point in other Microsoft surfaces.
The MCP standard itself is solid. If you've built MCP servers for Claude or other clients, the Copilot story is familiar. The Microsoft-specific parts are the UI extensions and the manifest, not the protocol itself.
Permissioning is granular. You can scope a Copilot extension to specific users or groups, which matters for enterprise rollouts where you don't want everyone in the tenant getting access to a beta extension.
What is still rough
Honest assessment, here's what's annoying:
Adaptive Card constraints. There's a finite set of what you can render. If you want a chart, you can embed a chart action but it's not as rich as a real charting library. If you want complex interactivity, you're going to hit limits. Plan accordingly.
The local development loop. Building, testing, and debugging an MCP app with UI is still more painful than building a web app. The feedback loop is slower and the error messages aren't always helpful.
Limited UI customisation. The cards live inside Copilot's chrome and you don't get full control over the experience. If your brand or design system needs to come through strongly, you'll be frustrated by what you can and can't change.
Documentation is incomplete. The Microsoft docs are growing fast but there are still gaps, particularly around the full app surface (the richer embedded experience). Expect to hit StackOverflow-type problems where the answer doesn't exist yet and you need to experiment.
State management. The card-based interaction model is request/response. Maintaining state across multiple user interactions takes some thought. You'll need to design how state lives - on your MCP server, in user context, or passed back via the cards themselves.
Patterns that have worked for us
A few patterns we've settled on after building a handful of these:
Start with cards, not full apps. The card surface is more constrained but it's faster to build and it covers most use cases. Only reach for the full embedded app surface when cards genuinely can't do what you need.
Treat the MCP app as a wrapper, not a rebuild. If you have an existing API or system, wrap it with an MCP server that exposes a thin set of operations. Don't rebuild your business logic in the MCP layer.
Design for the read-mostly case first. Most Copilot interactions are users asking for information, not submitting complex updates. Get the read experience right (clean cards, fast responses, useful actions) before building elaborate forms.
Plan your authentication scope carefully. The default is usually too broad. Scope tokens to the minimum your tool needs. Users will appreciate it when the consent prompt asks for less, and your security team will appreciate it later.
Build in observability from day one. You want to know how often your app is being invoked, what tools are being called, what errors are happening. Add logging and basic metrics. You'll need them.
We help organisations think through these design decisions as part of our Microsoft AI agent framework work and the MCP UI capability is increasingly the right answer for "we want this experience but inside Copilot".
Should you actually use this
Honest take: yes, but selectively. If you have a use case where:
The data or action lives in a system Copilot users would benefit from accessing in-chat
The interaction is primarily read or simple form submission, not complex multi-step workflows
You already have an API for the system or can build one
Your users are already on Copilot and would use it for this
Then yes, the MCP UI route is probably the right call. The development cost is non-trivial but the user experience benefit is real and the alternative (a separate app) often has its own adoption challenges.
If you're trying to use this to replace a full-featured internal application with rich UI and complex state, you're going to be disappointed. That's not what this is for. Use it for focused, well-scoped experiences that benefit from being where users already are.
What we expect to see next
A few predictions from where I'm sitting:
The full app surface will get better. Right now it's the rougher of the two options but Microsoft is clearly investing. Expect richer interaction and better tooling within the next 6-12 months.
More starter templates and reference apps. The early ones from Microsoft are useful but limited. Community examples will fill in the gaps.
Better local dev tooling. The current loop is painful enough that improving it is an obvious priority. Expect emulators and better debugging within the year.
Tighter integration with Copilot Studio. Right now MCP apps and Copilot Studio agents are somewhat separate worlds. Expect them to converge.
We're tracking all of this as part of our Australian AI consulting practice because clients keep asking what's the right surface for what use case. The answer keeps changing.
Final thoughts
MCP apps with UI are a real step forward for Copilot extensibility. They're not finished, the tooling is rough in places, and you'll hit limits with the card model. But for the right use cases they meaningfully change what you can build inside Copilot.
If you're considering building a Copilot extension, default to checking whether the MCP UI route works for your use case before reaching for a separate app or a Power Platform solution. It's increasingly the right starting point.
Microsoft's full guidance is at their MCP apps UI docs. It's the best reference for the technical specifics. This post is what I'd add about how to use it well in real client work.