<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Cowork on The Developer's Cantina</title><link>https://www.developerscantina.com/tags/cowork/</link><description>Recent content in Cowork on The Developer's Cantina</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Fri, 19 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://www.developerscantina.com/tags/cowork/index.xml" rel="self" type="application/rss+xml"/><item><title>From federated connectors to Cowork: using a MCP server for a plugin</title><link>https://www.developerscantina.com/p/cowork-mcp-connector/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://www.developerscantina.com/p/cowork-mcp-connector/</guid><description>&lt;img src="https://www.developerscantina.com/p/cowork-mcp-connector/cover.png" alt="Featured image of post From federated connectors to Cowork: using a MCP server for a plugin" /&gt;&lt;p&gt;In the &lt;a class="link" href="https://www.developerscantina.com/p/mcp-federated-connector/" &gt;previous post&lt;/a&gt;, we took an authenticated Model Context Protocol (MCP) server we had built ourselves and turned it into a &lt;strong&gt;federated Copilot Connector&lt;/strong&gt;, so that Researcher and Copilot Chat could query it live, on demand, without ingesting any data into the tenant. This post is a standalone follow-up, but it builds directly on that work: we&amp;rsquo;re going to reuse the exact same MCP server and, more importantly, the exact same Microsoft Entra client app registration and Teams Developer Portal OAuth registration. The output of the previous post is, quite literally, the input of this one.&lt;/p&gt;
&lt;p&gt;The reason I&amp;rsquo;m writing this comes from a real customer engagement. A customer expressed interest in building plugins for &lt;strong&gt;Microsoft 365 Copilot Cowork&lt;/strong&gt; to connect it with their own data. It was a new topic for me, so I started researching it, and while doing so I noticed something worth sharing: a federated connector and a Cowork plugin both authenticate their MCP connector through the &lt;strong&gt;same configuration model in the Teams Developer Portal&lt;/strong&gt;. In other words, the OAuth registration we already produced for the federated connector can be plugged straight into a Cowork plugin, without creating anything new.&lt;/p&gt;
&lt;p&gt;When you step back, this consistency makes sense. MCP server integration across the Microsoft 365 Copilot ecosystem follows the same pattern, and it now covers three different features:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Declarative agents&lt;/strong&gt; with authenticated MCP servers, which we &lt;a class="link" href="https://www.developerscantina.com/p/mcp-declarative-agent/" &gt;covered earlier on the blog&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Federated connectors&lt;/strong&gt;, the subject of the &lt;a class="link" href="https://www.developerscantina.com/p/mcp-federated-connector/" &gt;previous post&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cowork plugins&lt;/strong&gt;, which is what we&amp;rsquo;re going to explore here.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All three reuse the same Teams Developer Portal OAuth configuration to authenticate against the same Entra-protected MCP server. Once you&amp;rsquo;ve set up the authentication once, you can light up each of these surfaces by pointing them at it.&lt;/p&gt;
&lt;p&gt;As usual, before we get into the &lt;em&gt;how&lt;/em&gt;, let&amp;rsquo;s spend a moment understanding the &lt;em&gt;why&lt;/em&gt;, starting with what Cowork actually is. Let&amp;rsquo;s get started!&lt;/p&gt;
&lt;h2 id="what-is-copilot-cowork"&gt;What is Copilot Cowork?
&lt;/h2&gt;&lt;p&gt;Compared to agents and the standard Copilot Chat experience, &lt;strong&gt;Copilot Cowork completes multi-step tasks on your behalf&lt;/strong&gt;. Instead of answering a single question or running a single tool, you describe the outcome you want, and it grounds the work in your emails, meetings, files, and business data, powered by &lt;strong&gt;Work IQ&lt;/strong&gt;. Cowork plans the steps, picks the right skills and apps for the job, pauses for your approval at key checkpoints, and returns finished artifacts (a deck, a report, an email, or a status update) ready for your review. The mental model is less &amp;ldquo;chat assistant&amp;rdquo; and more &amp;ldquo;a colleague who takes a task, works through it, and comes back with a draft&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Cowork reached general availability on &lt;strong&gt;June 16, 2026&lt;/strong&gt;, with a &lt;a class="link" href="https://www.microsoft.com/microsoft-365/blog/2026/06/16/copilot-cowork-is-now-generally-available/" target="_blank" rel="noopener"
&gt;consumption billing model based on Copilot Credits&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Like the rest of the Copilot ecosystem, Cowork can be extended, and it&amp;rsquo;s extended using &lt;strong&gt;Skills&lt;/strong&gt;, which are prompt-based instructions that teach Cowork &lt;em&gt;how&lt;/em&gt; to perform a certain kind of task and &lt;em&gt;when&lt;/em&gt; to do it.
On top of the skills concept (which is a standard in the industry, supported by many tools and platforms), Cowork provides a plugin infrastructure, which adds two capabilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Connectors&lt;/strong&gt;, which give skills live reach into an external platform or service through an MCP server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Governance&lt;/strong&gt;. Plugins can be treated like agents or apps in the Microsoft 365 ecosystem, so they can be deployed, blocked, restricted to a set of users, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both skills and connectors are delivered together as a &lt;strong&gt;Microsoft 365 App Package&lt;/strong&gt;: a &lt;code&gt;.zip&lt;/code&gt; file with a manifest and its assets. This is the same distribution mechanism already used for Teams apps, Copilot agents, and Office add-ins, so if you&amp;rsquo;ve shipped any of those before, the packaging model will feel familiar.&lt;/p&gt;
&lt;h2 id="federated-connectors-vs-cowork-plugins"&gt;Federated connectors vs. Cowork plugins
&lt;/h2&gt;&lt;p&gt;Since we&amp;rsquo;re coming from the federated connector post, it&amp;rsquo;s worth drawing a clear line between the two, because they look similar but serve different purposes.&lt;/p&gt;
&lt;p&gt;Both achieve the same high-level goal: they enrich the Copilot experiences with additional capabilities by tapping into external platforms and services. The key differentiator is &lt;em&gt;what kind&lt;/em&gt; of capability they&amp;rsquo;re allowed to add:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;federated connector&lt;/strong&gt; is made to enrich &lt;strong&gt;knowledge&lt;/strong&gt;. It&amp;rsquo;s a querying surface, so it supports &lt;strong&gt;read-only&lt;/strong&gt; tools only. Its job is to bring live data into Copilot, not to change anything in the external system.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Cowork plugin&lt;/strong&gt; can go further. Because Cowork is built to &lt;em&gt;complete tasks&lt;/em&gt;, a plugin can use its MCP tools to &lt;strong&gt;take actions&lt;/strong&gt;, not just read data. The same MCP server that surfaces information can also be allowed to perform write operations on the external platform.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Our sample stays deliberately read-only, since it&amp;rsquo;s the same customer-and-invoice server from the previous post. But it&amp;rsquo;s important to know that the capability is there: if your MCP server exposes tools that create or update records, a Cowork plugin is able to call them.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the part that ties everything together, and the reason this post can be so short compared to the previous one: &lt;strong&gt;the authentication layer is identical and reused&lt;/strong&gt;. Same MCP server, same Microsoft Entra client app registration, same Teams Developer Portal OAuth registration and Reference ID. We don&amp;rsquo;t have to register a new application, expose a new scope, or create a new OAuth connection. Everything we did in the previous post applies here unchanged. All that&amp;rsquo;s left is to describe the connector to Cowork through a manifest.&lt;/p&gt;
&lt;h2 id="anatomy-of-the-plugin-package"&gt;Anatomy of the plugin package
&lt;/h2&gt;&lt;p&gt;As we mentioned, a Cowork plugin is a Microsoft 365 App Package, which is a &lt;code&gt;.zip&lt;/code&gt; file. With all the files placed at the &lt;strong&gt;root&lt;/strong&gt; of the archive, here&amp;rsquo;s what ours contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;manifest.json&lt;/code&gt;&lt;/strong&gt; — the Microsoft 365 Unified App Manifest (version 1.28) that declares the plugin, its skill, and its MCP connector.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;color.png&lt;/code&gt;&lt;/strong&gt; — the full-color app icon, 192x192 pixels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;outline.png&lt;/code&gt;&lt;/strong&gt; — the monochrome outline icon, 32x32 pixels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;toolDescription.json&lt;/code&gt;&lt;/strong&gt; — the description of the MCP server&amp;rsquo;s tools, in the format Cowork expects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;skills/customer-data-assistant/SKILL.md&lt;/code&gt;&lt;/strong&gt; — the skill that teaches Cowork when and how to use the connector.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;rsquo;s go through the two files that do the real work: the manifest, which wires up the connector, and the skill, which tells Cowork when to reach for it.&lt;/p&gt;
&lt;h2 id="declaring-the-connector-in-the-manifest"&gt;Declaring the connector in the manifest
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;manifest.json&lt;/code&gt; file is the heart of the package. It declares the plugin&amp;rsquo;s identity and icons (the standard fields you&amp;rsquo;d find in any Microsoft 365 app manifest), and then it references two things that matter for us: the skill, under &lt;code&gt;agentSkills&lt;/code&gt;, and the MCP connector, under &lt;code&gt;agentConnectors&lt;/code&gt;. Here&amp;rsquo;s the full file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;span class="lnt"&gt;37
&lt;/span&gt;&lt;span class="lnt"&gt;38
&lt;/span&gt;&lt;span class="lnt"&gt;39
&lt;/span&gt;&lt;span class="lnt"&gt;40
&lt;/span&gt;&lt;span class="lnt"&gt;41
&lt;/span&gt;&lt;span class="lnt"&gt;42
&lt;/span&gt;&lt;span class="lnt"&gt;43
&lt;/span&gt;&lt;span class="lnt"&gt;44
&lt;/span&gt;&lt;span class="lnt"&gt;45
&lt;/span&gt;&lt;span class="lnt"&gt;46
&lt;/span&gt;&lt;span class="lnt"&gt;47
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;$schema&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://developer.microsoft.com/json-schemas/teams/v1.28/MicrosoftTeams.schema.json&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;manifestVersion&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.28&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;your-app-guid&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;developer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Matteo Pagani&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;websiteUrl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://www.microsoft.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;privacyUrl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://www.microsoft.com/privacy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;termsOfUseUrl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://www.microsoft.com/legal&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;short&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Customer Data Assistant&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Customer Data Assistant for Copilot Cowork&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;short&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Look up customers and invoices via a custom MCP server.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;full&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Adds a Cowork skill and a remote MCP connector that let Copilot Cowork search, filter, and fetch read-only customer and invoice data exposed by a custom Model Context Protocol server over Streamable HTTP, secured with Microsoft Entra ID.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;icons&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;color&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;color.png&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;outline&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;outline.png&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;accentColor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;#4361EE&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;agentSkills&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nt"&gt;&amp;#34;folder&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./skills/customer-data-assistant&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;agentConnectors&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;mcp-data-server&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;displayName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Customer Data MCP Server&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Read-only access to customer and invoice records exposed by a custom MCP server.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;toolSource&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;remoteMcpServer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpServerUrl&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://&amp;lt;tunnel-id&amp;gt;-5000.euw.devtunnels.ms/mcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcpToolDescription&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;file&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;toolDescription.json&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;authorization&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;OAuthPluginVault&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;referenceId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;your-teams-developer-portal-reference-id&amp;gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Let&amp;rsquo;s take a look at the &lt;code&gt;agentConnectors&lt;/code&gt; block, since it&amp;rsquo;s the one that&amp;rsquo;s new compared to a plain skill-only package. Each entry describes a single connector: an &lt;code&gt;id&lt;/code&gt; and a &lt;code&gt;displayName&lt;/code&gt; that Cowork shows in the UI, a &lt;code&gt;description&lt;/code&gt;, and a &lt;code&gt;toolSource&lt;/code&gt;. For a remote MCP server, the &lt;code&gt;toolSource&lt;/code&gt; is a &lt;code&gt;remoteMcpServer&lt;/code&gt; object made of three parts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;mcpServerUrl&lt;/code&gt;&lt;/strong&gt; is the public URL of our MCP server, including the &lt;code&gt;/mcp&lt;/code&gt; path. It&amp;rsquo;s the very same endpoint we exposed through a dev tunnel in the previous post.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;mcpToolDescription&lt;/code&gt;&lt;/strong&gt; points to a &lt;code&gt;file&lt;/code&gt;, &lt;code&gt;toolDescription.json&lt;/code&gt;, which lists the tools the server exposes. We&amp;rsquo;ll look at this file in the next section.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;authorization&lt;/code&gt;&lt;/strong&gt; is where the reuse happens, and it deserves its own sub-section.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="reusing-the-reference-id"&gt;Reusing the Reference ID
&lt;/h3&gt;&lt;p&gt;The &lt;code&gt;authorization&lt;/code&gt; block uses the type &lt;strong&gt;&lt;code&gt;OAuthPluginVault&lt;/code&gt;&lt;/strong&gt;, and its &lt;code&gt;referenceId&lt;/code&gt; is the exact same &lt;strong&gt;Reference ID&lt;/strong&gt; that the Teams Developer Portal generated for us in the &lt;a class="link" href="https://www.developerscantina.com/p/mcp-federated-connector/" &gt;previous post&lt;/a&gt;, when we set up the OAuth client registration for the federated connector.&lt;/p&gt;
&lt;p&gt;This is the key point of the whole post: there&amp;rsquo;s &lt;strong&gt;no new Entra app registration and no new Teams Developer Portal registration&lt;/strong&gt; to create here. The OAuth connection we registered for the federated connector already knows how to obtain a token for our MCP server, on behalf of the signed-in user, using our dedicated client application. By referencing it through &lt;code&gt;OAuthPluginVault&lt;/code&gt;, the Cowork plugin reuses that same connection as-is, nothing more to configure.&lt;/p&gt;
&lt;p&gt;Remember to replace &lt;code&gt;&amp;lt;your-teams-developer-portal-reference-id&amp;gt;&lt;/code&gt; with the actual Reference ID you copied from the Teams Developer Portal when you created the OAuth connection in the previous post, and to replace &lt;code&gt;https://&amp;lt;tunnel-id&amp;gt;-5000.euw.devtunnels.ms/mcp&lt;/code&gt; with the real public URL of your MCP server, including the &lt;code&gt;/mcp&lt;/code&gt; path. For the sake of this demo we&amp;rsquo;re pointing at a dev tunnel; in a production scenario this would be the stable public endpoint where your server is hosted.&lt;/p&gt;
&lt;h2 id="describing-the-tools-with-tooldescriptionjson"&gt;Describing the tools with toolDescription.json
&lt;/h2&gt;&lt;p&gt;In the manifest, &lt;code&gt;mcpToolDescription&lt;/code&gt; points to a file rather than listing the tools inline. That file, &lt;code&gt;toolDescription.json&lt;/code&gt;, has a specific shape: it must be a JSON document that matches the server&amp;rsquo;s &lt;code&gt;tools/list&lt;/code&gt; response. In other words, it&amp;rsquo;s the same list of tools your MCP server would return when a client asks it what it can do, with a top-level &lt;code&gt;tools&lt;/code&gt; array where each entry has a &lt;code&gt;name&lt;/code&gt;, a &lt;code&gt;description&lt;/code&gt;, and an &lt;code&gt;inputSchema&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;span class="lnt"&gt;34
&lt;/span&gt;&lt;span class="lnt"&gt;35
&lt;/span&gt;&lt;span class="lnt"&gt;36
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;tools&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;search_customers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Search customers by a free-text term. Matches against id, name, email, company, city, country, and status. Returns a JSON array of matching customers.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;inputSchema&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;object&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Free-text term to search for. Leave empty to return all customers.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;limit&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;integer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Maximum number of results to return (default 20).&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;required&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;fetch_customer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Fetch a single customer by its exact id (for example, CUST-1001). Returns the customer as JSON, or an error message if not found.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;inputSchema&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;object&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;customerId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;The exact customer id, e.g. CUST-1001.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;required&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;customerId&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;As you can see, each tool entry mirrors exactly what the MCP server advertises: the &lt;code&gt;name&lt;/code&gt; Cowork will call, a &lt;code&gt;description&lt;/code&gt; that helps the model decide when the tool is appropriate, and an &lt;code&gt;inputSchema&lt;/code&gt; (a JSON Schema object) that declares the parameters and which of them are required. I&amp;rsquo;ve shown two of the seven tools here, &lt;code&gt;search_customers&lt;/code&gt; and &lt;code&gt;fetch_customer&lt;/code&gt;; the remaining five follow the same shape.&lt;/p&gt;
&lt;p&gt;For reference, the full set of seven tools our server exposes is: &lt;code&gt;search_customers&lt;/code&gt;, &lt;code&gt;fetch_customer&lt;/code&gt;, &lt;code&gt;query_customers&lt;/code&gt;, &lt;code&gt;count_customers&lt;/code&gt;, &lt;code&gt;search_invoices&lt;/code&gt;, &lt;code&gt;fetch_invoice&lt;/code&gt;, and &lt;code&gt;query_invoices&lt;/code&gt;. Since this is the format the file expects, the cleanest way to produce it is to take your server&amp;rsquo;s actual &lt;code&gt;tools/list&lt;/code&gt; output and wrap it as shown above.&lt;/p&gt;
&lt;h2 id="teaching-cowork-when-to-use-the-connector-the-skill"&gt;Teaching Cowork when to use the connector: the skill
&lt;/h2&gt;&lt;p&gt;Declaring the connector makes the tools &lt;em&gt;available&lt;/em&gt;, but it doesn&amp;rsquo;t tell Cowork &lt;em&gt;when&lt;/em&gt; it should reach for them. That&amp;rsquo;s the job of the skill, which lives under &lt;code&gt;skills/customer-data-assistant/SKILL.md&lt;/code&gt;. This is the same skills format Cowork uses on its own; the only difference is that our skill is paired with a connector and routes the user&amp;rsquo;s requests to its tools.&lt;/p&gt;
&lt;p&gt;A &lt;code&gt;SKILL.md&lt;/code&gt; file is made of two parts: a YAML frontmatter block and a Markdown body. The frontmatter is the most important part, because its &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; are what Cowork reads to decide whether the skill is relevant to what the user is asking. Here&amp;rsquo;s our frontmatter:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;customer-data-assistant&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;-&lt;/span&gt;&lt;span class="sd"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; Use when the user asks about customers or invoices held in the company data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; system: looking up a customer or invoice by id, searching or filtering them,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; counting customers by status, or reviewing invoice totals and line items.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; Trigger on requests like &amp;#34;find customer CUST-1001&amp;#34;, &amp;#34;show open invoices in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; EUR&amp;#34;, &amp;#34;how many active customers do we have&amp;#34;, &amp;#34;what does invoice INV-2003
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; contain&amp;#34;, or &amp;#34;list customers in Italy&amp;#34;. Backed by the read-only
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="sd"&gt; &amp;#34;mcp-data-server&amp;#34; connector.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nn"&gt;---&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Notice how the &lt;code&gt;description&lt;/code&gt; does two things at once. It explains the &lt;em&gt;domain&lt;/em&gt; the skill covers (customers and invoices held in the company data system), and it gives Cowork concrete &lt;strong&gt;trigger phrases&lt;/strong&gt;, like &lt;em&gt;&amp;ldquo;find customer CUST-1001&amp;rdquo;&lt;/em&gt; or &lt;em&gt;&amp;ldquo;how many active customers do we have&amp;rdquo;&lt;/em&gt;. Those example prompts are what help Cowork match a real user request to this skill. The final sentence ties the skill to the connector by naming it: the read-only &lt;code&gt;mcp-data-server&lt;/code&gt; connector we declared in the manifest.&lt;/p&gt;
&lt;p&gt;The body of the file then describes how to use the connector once the skill has been selected. It contains an &lt;strong&gt;Available tools&lt;/strong&gt; section that lists the seven tools with when-to-use guidance, a set of &lt;strong&gt;routing rules&lt;/strong&gt;, an &lt;strong&gt;output format&lt;/strong&gt; section, and read-only guardrails. The routing rules are the practical heart of it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Routing rules
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; The user gives an &lt;span class="gs"&gt;**exact id**&lt;/span&gt; (CUST-1001, INV-2003) → use &lt;span class="sb"&gt;`fetch_customer`&lt;/span&gt; / &lt;span class="sb"&gt;`fetch_invoice`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; The user gives a &lt;span class="gs"&gt;**loose term**&lt;/span&gt; (a name, a company, a city) → use &lt;span class="sb"&gt;`search_customers`&lt;/span&gt; / &lt;span class="sb"&gt;`search_invoices`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; The user asks for a &lt;span class="gs"&gt;**specific field filter**&lt;/span&gt; (status, country, currency) → use &lt;span class="sb"&gt;`query_customers`&lt;/span&gt; / &lt;span class="sb"&gt;`query_invoices`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;-&lt;/span&gt; The user asks &lt;span class="ge"&gt;**&lt;/span&gt;&amp;#34;how many&amp;#34;** customers → use &lt;span class="sb"&gt;`count_customers`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;This is what makes Cowork reach for the connector&amp;rsquo;s tools at the right time and pick the right one. The frontmatter gets the skill selected when the conversation is about customers or invoices; the routing rules in the body then translate the shape of the user&amp;rsquo;s request into the most appropriate tool call. Together, the skill is the &amp;ldquo;know-how&amp;rdquo; layer sitting on top of the connector&amp;rsquo;s live reach.&lt;/p&gt;
&lt;h2 id="deploying-the-plugin"&gt;Deploying the plugin
&lt;/h2&gt;&lt;p&gt;Now that we have the package, we need to get it into Cowork. There are two ways to do this, depending on whether you want to try it yourself or roll it out to everyone.&lt;/p&gt;
&lt;p&gt;The first option is to &lt;strong&gt;test it for yourself&lt;/strong&gt;, which is what you&amp;rsquo;ll want during development. We can sideload the package using the &lt;a class="link" href="https://learn.microsoft.com/microsoftteams/platform/toolkit/microsoft-365-agents-toolkit-cli" target="_blank" rel="noopener"
&gt;Microsoft 365 Agents Toolkit CLI&lt;/a&gt; (&lt;code&gt;atk&lt;/code&gt;). The &lt;code&gt;install&lt;/code&gt; command takes the path to our &lt;code&gt;.zip&lt;/code&gt; and a scope:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;atk&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="o"&gt;-file&lt;/span&gt;&lt;span class="n"&gt;-path&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;lt;path-to&amp;gt;\cowork-mcp-plugin.zip&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;-scope&lt;/span&gt; &lt;span class="n"&gt;Personal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Remember to replace &lt;code&gt;&amp;lt;path-to&amp;gt;&lt;/code&gt; with the actual folder where your package lives. The &lt;code&gt;Personal&lt;/code&gt; scope installs the plugin just for your own account, which is exactly what you want while you&amp;rsquo;re iterating on it.&lt;/p&gt;
&lt;p&gt;The second option is to &lt;strong&gt;publish it to the whole organization&lt;/strong&gt;. Because a Cowork plugin is a Microsoft 365 App Package, you publish it exactly like you&amp;rsquo;d publish a Teams application: you upload the package through the &lt;strong&gt;Microsoft 365 Admin Center&lt;/strong&gt; and make it available to your users from there. For day-to-day development, the &lt;code&gt;atk install&lt;/code&gt; route is quicker; for an organization-wide rollout, the Admin Center is the way to go.&lt;/p&gt;
&lt;h2 id="trying-it-out-in-cowork"&gt;Trying it out in Cowork
&lt;/h2&gt;&lt;p&gt;Once the plugin is installed, it shows up in Cowork. On its plugin page we can see both pieces we packaged: the &lt;strong&gt;Customer Data MCP Server&lt;/strong&gt; connector (with a &lt;strong&gt;Connect&lt;/strong&gt; button to run the OAuth flow the first time) and the &lt;code&gt;customer-data-assistant&lt;/code&gt; skill.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.developerscantina.com/p/cowork-mcp-connector/cowork-plugin-page.png"
width="1216"
height="958"
loading="lazy"
alt="The Customer Data Assistant plugin installed in Cowork, showing its MCP connector and skill"
class="gallery-image"
data-flex-grow="126"
data-flex-basis="304px"
&gt;&lt;/p&gt;
&lt;p&gt;After connecting (which triggers the same OAuth flow we set up in the previous post, now reused through the Reference ID), we can put it to work. The prompt I used was deliberately simple:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I need a list of customers&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Cowork matched the request to our skill, called the connector&amp;rsquo;s tools, and returned all six customers as a table, complete with a summary line:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://www.developerscantina.com/p/cowork-mcp-connector/cowork-customers-result.png"
width="1227"
height="861"
loading="lazy"
alt="Cowork returning the list of customers through the MCP connector"
class="gallery-image"
data-flex-grow="142"
data-flex-basis="342px"
&gt;&lt;/p&gt;
&lt;p&gt;As you can see, our own MCP server is now answering a Cowork prompt with live data, through a plugin we packaged ourselves. We did it!&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up
&lt;/h2&gt;&lt;p&gt;In this post, we took the authenticated MCP server and the OAuth registration we&amp;rsquo;d already built for our federated connector, and we reused them to add the same server as a connector inside a Microsoft 365 Copilot Cowork plugin, paired with a skill that tells Cowork when to use it.&lt;/p&gt;
&lt;p&gt;To summarize, here are the steps we went through:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Reviewed what Cowork is and how it&amp;rsquo;s extended&lt;/strong&gt;, through skills (prompt-based know-how) and connectors (live reach into an external system), both delivered as a Microsoft 365 App Package.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Packaged the plugin&lt;/strong&gt; as a &lt;code&gt;.zip&lt;/code&gt; with the manifest, the icons, the tool description, and the skill at its root.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Declared the MCP connector in the manifest&lt;/strong&gt;, under &lt;code&gt;agentConnectors&lt;/code&gt;, pointing &lt;code&gt;mcpServerUrl&lt;/code&gt; at our server and &lt;code&gt;authorization&lt;/code&gt; at the existing Teams Developer Portal Reference ID through &lt;code&gt;OAuthPluginVault&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Described the tools in &lt;code&gt;toolDescription.json&lt;/code&gt;&lt;/strong&gt;, in the format that matches the server&amp;rsquo;s &lt;code&gt;tools/list&lt;/code&gt; response.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authored the skill&lt;/strong&gt; in &lt;code&gt;SKILL.md&lt;/code&gt;, whose frontmatter and routing rules make Cowork reach for the connector&amp;rsquo;s tools at the right time.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deployed the plugin&lt;/strong&gt;, either for ourselves with the Microsoft 365 Agents Toolkit CLI (&lt;code&gt;atk install ... --scope Personal&lt;/code&gt;) or for the whole organization through the Microsoft 365 Admin Center.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tried it out in Cowork&lt;/strong&gt;, where a simple &lt;em&gt;&amp;ldquo;I need a list of customers&amp;rdquo;&lt;/em&gt; prompt returned live data from our server.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The thing worth taking away is the consistency: the same MCP server and the same OAuth registration that powered our federated connector now light up a Cowork plugin too, completing the trio across the Microsoft 365 Copilot ecosystem alongside declarative agents. Set up the authentication once, and you can reuse it everywhere.&lt;/p&gt;
&lt;p&gt;You can find the complete source code of the MCP server &lt;a class="link" href="https://github.com/qmatteoq/MCP-FederatedConnector" target="_blank" rel="noopener"
&gt;on GitHub&lt;/a&gt;. If you want to dig into the official references, the &lt;a class="link" href="https://learn.microsoft.com/microsoft-365/copilot/cowork/cowork-plugin-development" target="_blank" rel="noopener"
&gt;Cowork plugin development&lt;/a&gt; documentation and the &lt;a class="link" href="https://learn.microsoft.com/microsoftteams/platform/m365-apps/agent-connectors" target="_blank" rel="noopener"
&gt;agent connectors&lt;/a&gt; reference cover the manifest and connector format in detail. And if you haven&amp;rsquo;t read them yet, the &lt;a class="link" href="https://www.developerscantina.com/p/mcp-federated-connector/" &gt;federated connector&lt;/a&gt; and &lt;a class="link" href="https://www.developerscantina.com/p/mcp-declarative-agent/" &gt;declarative agent&lt;/a&gt; posts complete the picture of how the same authenticated MCP server fits across the Microsoft 365 Copilot ecosystem.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Part 1 — &lt;a class="link" href="https://www.developerscantina.com/p/mcp-federated-connector/" &gt;From MCP server to Copilot data source: building a federated connector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.developerscantina.com/p/mcp-declarative-agent/" &gt;Declarative agents with authenticated MCP servers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/qmatteoq/MCP-FederatedConnector" target="_blank" rel="noopener"
&gt;MCP-FederatedConnector on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/microsoft-365/copilot/cowork/cowork-plugin-development" target="_blank" rel="noopener"
&gt;Cowork plugin development documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://learn.microsoft.com/microsoftteams/platform/m365-apps/agent-connectors" target="_blank" rel="noopener"
&gt;Agent connectors reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>