The AI community has collectively decided that MCP servers are the best way for agents to use remote tools. (...right?)
Once every agent client speaks MCP, the next problem is that every client still packages MCP differently. Agent Plugins is a new attempt to make that layer portable: one package for Agent Skills and MCP servers, backed by maintainers from Amazon, Cursor, Microsoft, OpenAI, and Vercel.
We wanted to use it with Microsoft 365 Copilot Cowork. Cowork does not consume Agent Plugins, but supports a plugin format which, at least in principle, mirrors an agent plugin. Luckily, Microsoft publishes a PowerShell script that converts Claude Code plugins into Cowork packages, so we thought we’d start there.
But a specification is different than a standard, as we learned.
A converter should be boring
An Agent Plugin is a small directory:
plugin.json
skills/
mcp.json
Cowork asks for the same basic ingredients inside a strict Microsoft 365 app manifest. A converter should preserve the skills and MCP endpoints, write an acceptable zip, and disappear from the story.
And Microsoft had already written 95% of what we needed.
Microsoft’s converter broke three different ways
We downloaded Microsoft’s documented Convert-ClaudePluginToMOS3.ps1 on 12 August 2026 and gave it one skill, one HTTPS MCP server, and ordinary author metadata.
It failed before producing a zip. Supplying source icons got us a package. Microsoft’s validator then failed twice more:
| Attempt | What the official script did | Result |
|---|---|---|
| 1 | Tried to generate a missing outline.png with System.Drawing. | Crashed inside Windows.Win32.PInvokeGdiPlus on PowerShell 7/macOS. |
| 2 | Wrote manifest.json with a UTF-8 byte-order mark. | ATK passed the bytes to JSON.parse, which rejected its first character. |
| 3 | Added developer.contactInfo when the plugin author had an email. | ATK rejected the object shape during manifest conversion. |
It also warned that the generated packageName field is deprecated.
Three failures across three different layers: packaging, parsing, schema. We filed a reproducible issue with the exact script hash and output.
No worries, we’ll whip one up from scratch. Conceptually, all we’re doing is copying folders and writing a manifest. And, hey, maybe we can share it with the community if it adds value.
The plan
Agent Plugins v1.0.0 gave us a cleaner input contract. Most of it mapped without drama:
| Agent Plugin input | Cowork result |
|---|---|
| Name, version, description, author | ✅ Microsoft 365 manifest metadata. |
skills/<name>/SKILL.md | ✅ Cowork Agent Skills. |
Headerless HTTPS streamable-http server | 👌 Remote Cowork MCP connector. |
stdio or legacy HTTP+SSE server | 👍 No supported target. |
| Literal HTTP headers | 🤨 No faithful Cowork field. |
Our rule was simple: translate only what keeps the same meaning. Everything else gets flagged.
Two specs, one hour, we thought.
The package was portable. Authentication wasn’t.
Agent Plugins says literal headers are visible package data and must not contain secrets. It is equally explicit about the larger boundary:
Agent Plugins 1.0.0 defines no OAuth configuration or portable credential-reference fields. Authorization discovery, user interaction, and credential storage are client-managed.
At this point, I’m starting to wonder which MCP servers will actually fit all these criteria and/or how we suddenly need a lot of user input to faithfully map a single server.
Because on the one hand, leaving auth out of a public plugin spec is justifiable. On the other, it means a converter cannot tell whether a server is public, supports MCP OAuth discovery, needs an API key, or requires a pre-registered OAuth client, and it means there will necessarily be more specs to follow 😅
And Cowork had its own selection of auth choices: None, OAuthPluginVault, ApiKeyPluginVault, or Dynamic Client Registration. The vault modes need something called a referenceId, which was an additional layer of abstraction on top of the auth data and used none of the normal suspects like Azure Key Vault.
The PowerShell converter, it turns out, guessed here when converting from Claude plugins. It took any external HTTPS endpoint and turned it into an OAuthPluginVault, handing back a plausible-looking referenceId whether or not the server could be registered.
It compiled, but didn’t work.
So we built the converter, if it still deserves that name: Agent Plugin CLI. And since we were more than halfway there already, we turned it into a general-purpose plugin CLI which can convert plugins or create ones from scratch, including generating skills and helping you fill in the blanks for auth.
Then Microsoft replied
The next morning, an ATK maintainer politely pointed out that the toolkit already had a related command, atk import openplugin, and that their team did not maintain the PowerShell script. They also pointed us to PR #16540 for the open Agent Plugins v1 work.
Our bad. Microsoft’s docs sent us to one converter, and we’d filed its bugs against the team that owned another.
So we gave ATK 1.1.15 the exact same fixture. It generated cross-platform placeholder icons. It wrote BOM-free JSON. It omitted the invalid contactInfo. Then atk package produced a zip and atk validate reported 57 passes and one harmless description warning.
The maintained converter worked for packaging.
Then we opened the connector it generated. Its default Auto mode had turned Microsoft’s public Learn MCP endpoint into OAuthPluginVault and generated repro-plugin-public-docs-auth as the referenceId. The package was valid. ATK had not created that registration, and the endpoint did not need one.
Passing --default-auth-type None fixed this server. It would be the wrong answer for an authenticated one. And a single global default still cannot faithfully describe a plugin containing both.
The open Agent Plugins v1 work in ATK preserves the same heuristic. So we thanked the maintainer, closed our original issue, and opened a focused follow-up for unresolved auth.
The first bug was in a converter owned somewhere else. The deeper problem had reproduced itself in both.
The missing contract
Agent Plugins does not need to standardize credential storage. It needs a portable way to describe a server’s non-secret authentication requirements, or a standard way for clients to negotiate them.
We opened an Agent Plugins v2 discussion for that missing contract. The answer could be a tiny requirements declaration or capability negotiation. The important part is making the unresolved requirement visible without pretending the credential itself is portable.
The package moved. The authority was guessed.
Oh well. Back to wiring it up by hand until either side can describe the decision without making it for us.
Sources
- 01Agent Plugins
Project overview and the portable package’s stated purpose.
- 02Agent Plugins v1.0.0 specification
Canonical package fields, visible-header rule, and client-managed authorization boundary.
- 03Agent Plugins launch announcement
OpenAI’s announcement of the shared package format and participating companies.
- 04Agent Plugins maintainers
Current project maintainers and affiliations.
- 05Build plugins for Copilot Cowork
Microsoft’s documented Cowork package path and link to its converter.
- 06Microsoft Claude-to-Cowork conversion script
The exact script exercised in this test.
- 07ATK Agent Plugins v1 import/export pull request
The maintained project converter and its pending Agent Plugins v1 update.
- 08Microsoft Teams manifest v1.28 schema
The strict target manifest contract used by Cowork packages.
- 09MCP authorization specification
Protocol-level authorization discovery and flow.