One Protocol to Rule Them All
MCP (the Model Context Protocol) lets a tool server work with Microsoft 365 Copilot, Claude, ChatGPT, VS Code, and any future MCP-compatible client. No vendor lock-in, no rewriting endpoints for every platform.
In this post we’ll take an existing MCP server, register it as a plugin in a declarative agent with OAuth authentication, and let Copilot orchestrate it alongside knowledge sources.
What Is MCP?
MCP is an open standard that defines how AI applications connect to external tools and data sources. Think of it as a contract: your server says “here are the tools I offer, here are the parameters they accept, here’s what they return”, and any MCP-compatible client knows exactly how to call them.
An MCP server exposes three kinds of capabilities:
- Tools: Actions the agent can invoke (create a ticket, send a message, run a query)
- Resources: Data the agent can read (configuration, reference docs, live state)
- Prompts: Reusable prompt templates the agent can leverage
For declarative agents in M365 Copilot, we mostly care about tools. They’re how your agent does things in the real world, and they come with typed parameters, validation, and structured results baked right in.
MCP was created by Anthropic and has since been adopted across the industry. The protocol spec and SDKs are open source, which means you’re not betting on any single vendor when you invest in MCP.
Why MCP Over API Plugins?
Both API plugins and MCP servers let your agent call external services, but they serve different purposes:
API Plugins are built on OpenAPI specs. They’re deeply integrated into the Microsoft 365 ecosystem with features like adaptive card rendering, built-in OAuth flows, and rich response semantics. If you already have a REST API with an OpenAPI spec, wrapping it as an API plugin is the path of least resistance.
MCP Servers give you portability. The same server you connect to Copilot also works with Claude, ChatGPT, VS Code, and every other MCP client. You get a standardized tool protocol that works across the entire AI ecosystem, and Copilot handles the integration through its plugin system.
| Criteria | API Plugin | MCP Server |
|---|---|---|
| Protocol | REST + OpenAPI | Model Context Protocol |
| Portability | Copilot-specific | Works with any MCP client |
| Best for | Well-defined REST APIs | Action-heavy tool integrations |
| Auth | OAuth, API key (built-in) | OAuth (via plugin manifest) |
| Rendering | Adaptive cards support | Text responses |
| Ecosystem | Microsoft 365 native | Cross-platform open standard |
My rule of thumb: if you have an existing REST API, use an API plugin. If you have an MCP server (or want tooling that works beyond Copilot), integrate it as an MCP plugin. Most production agents use a mix of both, and that’s exactly what we’re doing with our Zava Insurance scenario.
You don’t have to choose one or the other. Declarative agents can register both API plugins and MCP servers in the same manifest. Use each where it shines.
Integrating an MCP Server as a Plugin
Let’s integrate a helpdesk MCP server for Zava Insurance, a fictional company whose HR team wants agents to create and track support tickets. We’ll assume the MCP server is already built and deployed (it exposes tools like createTicket and getTicketStatus over Streamable HTTP). Our job is to wire it into a declarative agent.
Create the Plugin Manifest
Since this MCP server handles employee data, we need OAuth authentication. Create an mcpPlugin.json in your appPackage/ folder with the OAuth configuration:
{
"schema_version": "v2.4",
"name_for_human": "Helpdesk",
"namespace": "ZavaHelpdesk",
"description_for_human": "Create and track IT support tickets for Zava Insurance.",
"runtimes": [
{
"type": "RemoteMCPServer",
"auth": {
"type": "OAuthPluginVault",
"reference_id": "${{OAUTH2AUTHCODE_CONFIGURATION_ID}}"
},
"spec": {
"url": "https://zava-helpdesk-mcp.azurewebsites.net/mcp",
"mcp_tool_description": {
"file": "mcp-tools.json"
}
}
}
]
}
The runtime type RemoteMCPServer tells Copilot this action points to an MCP server rather than a REST API. The auth block uses OAuthPluginVault with a reference_id that points to the OAuth client registration, exactly the same pattern as API plugins. Copilot handles the full OAuth 2.1 flow, consent prompts, and token injection for you.
The mcp_tool_description property references an mcp-tools.json file in your app package. This file contains the tool definitions that match the format returned by the MCP server’s tools/list method. You can grab this by calling your MCP server’s tools/list endpoint and saving the result:
[
{
"name": "createTicket",
"description": "Create a new support ticket for an employee",
"inputSchema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Short summary of the issue"
},
"description": {
"type": "string",
"description": "Detailed description of the problem"
},
"priority": {
"type": "string",
"enum": ["low", "medium", "high"],
"description": "Ticket priority level"
}
},
"required": ["title", "description", "priority"]
}
},
{
"name": "getTicketStatus",
"description": "Look up the current status of a support ticket",
"inputSchema": {
"type": "object",
"properties": {
"ticketId": {
"type": "string",
"description": "The ticket ID to look up (e.g., HR-4127)"
}
},
"required": ["ticketId"]
}
}
]
Copilot uses these tool descriptions to decide when to invoke each tool, so make your description fields count.
Automate the OAuth Registration
You don’t need to register OAuth credentials manually in the Teams Developer Portal. The M365 Agents Toolkit automates this through your m365agents.yml configuration file:
provision:
- uses: oauth/register
with:
name: oAuth2AuthCode
flow: authorizationCode
appId: ${{TEAMS_APP_ID}}
clientId: ${{AAD_APP_CLIENT_ID}}
clientSecret: ${{SECRET_AAD_APP_CLIENT_SECRET}}
writeToEnvironmentFile:
configurationId: OAUTH2AUTHCODE_CONFIGURATION_ID
During provisioning, the toolkit registers the OAuth client in the Developer Portal and writes the resulting configuration ID back as OAUTH2AUTHCODE_CONFIGURATION_ID. Any ${{OAUTH2AUTHCODE_CONFIGURATION_ID}} placeholder in your plugin manifest resolves automatically, so you never have to copy-paste registration IDs by hand.
Reference the Plugin in Your Agent
Add the plugin to your declarativeAgent.json actions array:
"actions": [
{
"id": "helpdeskMcpServer",
"file": "mcpPlugin.json"
}
]
Place mcpPlugin.json in your appPackage/ folder alongside declarativeAgent.json. The file path is relative to the manifest location.
That’s it. No server code to write, no middleware to configure. You’ve connected an existing MCP server to your declarative agent with proper OAuth authentication.
The Zava Insurance Helpdesk in Action
Here’s how it plays out:
Later that day, the employee asks:
No portal-hopping, no searching through email threads.
In the same conversation, the employee can ask “What does the remote work policy say about working from home while my badge is being fixed?”, and the agent switches from the MCP server to the embedded knowledge sources, answering with a citation from the Employee Handbook. Zero routing logic on our part. The declarative agent orchestrates between tools and knowledge automatically.
The Value of MCP Plugins
Integrating MCP servers as plugins gives you concrete advantages:
- Portability: Your Zava Insurance helpdesk server works with Copilot today, Claude tomorrow, and whatever comes next. Build once, connect everywhere.
- Ecosystem access: The MCP ecosystem is growing fast. Hundreds of servers already exist for databases, APIs, developer tools, and enterprise systems. You can integrate them into your agents without building anything from scratch.
- Composability: Agents can mix MCP tools, API plugins, and knowledge sources in a single conversation. The declarative agent orchestrates across all of them automatically.
- Standardized auth: Copilot handles the full OAuth 2.1 flow with PKCE. Your MCP server receives a validated bearer token on every request, just like any other protected API.
Resources
Have questions or want to share what you're building? Connect with me on LinkedIn or check out more on The Manifest.