M365 Copilot Cowork (Frontier) — remote MCP connector with OAuthPluginVault authenticates but tool calls fail in chat

Syed Raza 0 Reputation points
2026-06-13T14:09:13.79+00:00

n Microsoft 365 Copilot Cowork (Frontier), a custom remote MCP server connector declared via agentConnectors → toolSource.remoteMcpServer:

  • Works perfectly when authorization.type = "None".
  • With authorization.type = "OAuthPluginVault" (Entra OAuth), the connector connects and completes the OAuth consent successfully, skills load, but every tool invocation from chat fails ("…the connector isn't responding in this session"). The server never receives an authenticated tool call.

The same MCP server and the same OAuth client registration work end-to-end with full per-user OAuth in a declarative agent in Microsoft 365 Copilot chat (m365.cloud.microsoft/chat). Only Cowork's OAuthPluginVault path fails.

This looks like Cowork is not carrying the connector's OAuth token into chat-time tool calls.

Environment

  • Microsoft 365 Copilot Cowork (Frontier preview), plugin sideloaded via M365 Admin Center → Manage Apps.
  • App package: M365 unified manifest v1.28, contains agentSkills + one agentConnectors entry.
  • MCP server: .NET 8, official ModelContextProtocol / ModelContextProtocol.AspNetCore SDK, Streamable HTTP transport, public HTTPS (TLS 1.2+), behind nginx at https://<your-domain>/mcp/.
  • Auth: Microsoft Entra ID. Single app registration, multi-tenant; OAuth client registration created in Teams Developer Portal with usage = "Any Microsoft 365 Organization"; exposes scope api://<app-id>/access_as_user; requestedAccessTokenVersion = 2. Redirect URIs include https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect and https://teams.microsoft.com/api/platform/v1.0/oAuthConsentRedirect.

Connector manifest (sanitized)

"agentConnectors": [

  {

    "id": "cts-cowork-server",

    "displayName": "CTS Inbox Agent",

    "description": "Entra-secured MCP server",

    "toolSource": {

      "remoteMcpServer": {

        "mcpServerUrl": "https://<your-domain>/mcp/",

        "authorization": {

          "type": "OAuthPluginVault",

          "referenceId": "<oauth-client-registration-id>"

        }

      }

    }

  }

]

(Tools are discovered dynamically; behavior is identical with or without a static mcpToolDescription.)

What works ✅

  1. authorization.type = "None" on the exact same connector/server → Cowork connects, discovers tools, and invokes them correctly in chat. So the transport, dynamic discovery (initialize / tools/list / tools/call, Streamable HTTP), and tool schemas are all compatible with Cowork.
  2. The same OAuth client registration (referenceId) and the same MCP server, used by a declarative agent in M365 Copilot chat, work end-to-end: the OAuth consent succeeds and tool calls arrive at the server bearing a valid Entra v2 access token (aud = the API app, azp = the client app, scp = access_as_user, correct issuer). The server validates it and returns live data.

What fails ❌

With authorization.type = "OAuthPluginVault" in Cowork:

  1. In Sources & Skills, the connector appears and "Connect" / sign-in completes successfully (Entra consent succeeds — no AADSTS error).
  2. Skills load in chat.
  3. When the user asks something that triggers a connector tool, Cowork responds with a message like "I'm unable to reach the connector — it isn't responding in this session."
  4. Server-side during the failure: the connect/validation phase reaches the server, but chat-time tool invocations do not arrive at the server as authenticated calls. (The server logs every request, including unauthenticated ones, which it correctly rejects with 401 while EnforceAuth = true. During the chat-time failure, no valid authenticated tool call is received.)

What I've ruled out

  • MCP transport / discovery — Cowork's own docs state it uses Streamable HTTP with dynamic discovery; my server supports initialize / tools/list / tools/call, and a Microsoft Copilot client (the declarative agent) completes full sessions against it.
  • Tool schema completeness — tools expose full JSON inputSchema; the None-auth connector invokes them fine.
  • The OAuth registration itself — it mints valid per-user v2 tokens that my server accepts; verified by the declarative agent working with the identical referenceId.
  • Redirect URIs / consent — the OAuth/consent step in Cowork succeeds; there is no AADSTS failure in Entra sign-in logs at connect time.
  • Server availability / auth enforcement — server is up; anonymous requests are correctly 401 with EnforceAuth = true; the None-auth path only works when enforcement is disabled.

Conclusion / the question

Everything points to a Cowork-side issue in the OAuthPluginVault flow: the connector authenticates at connect time, but the acquired token is not bound to / sent on chat-time MCP tool calls, so the server never receives an authenticated request and the tool call fails.

  • Is this a known limitation/bug in the current Cowork (Frontier) preview for third-party remote MCP connectors using OAuthPluginVault?
  • Is there any additional manifest, registration, or scope configuration required for Cowork specifically (vs. a declarative agent) to carry the user token into tool calls?
  • If it's a known preview gap, is there an ETA or a supported interim pattern for per-user authenticated custom MCP connectors in Cowork (i.e., something other than None, which is anonymous and unacceptable for production data)?

User's image

User's image

Minimal repro

  1. Stand up a remote MCP server (Streamable HTTP) that requires an Entra bearer token.
  2. Register an OAuth client (TDP, "Any Microsoft 365 Organization") for it.
  3. Package a Cowork plugin with one agentConnectors → remoteMcpServer using OAuthPluginVault + that referenceId. Sideload.
  4. Connect the connector in Sources & Skills (consent succeeds), then ask chat to use a tool → fails; server receives no authenticated tool call.
  5. Switch the same connector to authorization.type = "None" (and allow anonymous on the server) → works. Use the same referenceId in a declarative agent in M365 Copilot chat → works.

 

n Microsoft 365 Copilot Cowork (Frontier), a custom remote MCP server connector declared via agentConnectors → toolSource.remoteMcpServer:

  • Works perfectly when authorization.type = "None".
  • With authorization.type = "OAuthPluginVault" (Entra OAuth), the connector connects and completes the OAuth consent successfully, skills load, but every tool invocation from chat fails ("…the connector isn't responding in this session"). The server never receives an authenticated tool call.

The same MCP server and the same OAuth client registration work end-to-end with full per-user OAuth in a declarative agent in Microsoft 365 Copilot chat (m365.cloud.microsoft/chat). Only Cowork's OAuthPluginVault path fails.

This looks like Cowork is not carrying the connector's OAuth token into chat-time tool calls.

Environment

  • Microsoft 365 Copilot Cowork (Frontier preview), plugin sideloaded via M365 Admin Center → Manage Apps.
  • App package: M365 unified manifest v1.28, contains agentSkills + one agentConnectors entry.
  • MCP server: .NET 8, official ModelContextProtocol / ModelContextProtocol.AspNetCore SDK, Streamable HTTP transport, public HTTPS (TLS 1.2+), behind nginx at https://<your-domain>/mcp/.
  • Auth: Microsoft Entra ID. Single app registration, multi-tenant; OAuth client registration created in Teams Developer Portal with usage = "Any Microsoft 365 Organization"; exposes scope api://<app-id>/access_as_user; requestedAccessTokenVersion = 2. Redirect URIs include https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect and https://teams.microsoft.com/api/platform/v1.0/oAuthConsentRedirect.

Connector manifest (sanitized)

"agentConnectors": [

  {

    "id": "cts-cowork-server",

    "displayName": "CTS Inbox Agent",

    "description": "Entra-secured MCP server",

    "toolSource": {

      "remoteMcpServer": {

        "mcpServerUrl": "https://<your-domain>/mcp/",

        "authorization": {

          "type": "OAuthPluginVault",

          "referenceId": "<oauth-client-registration-id>"

        }

      }

    }

  }

]

(Tools are discovered dynamically; behavior is identical with or without a static mcpToolDescription.)

What works ✅

  1. authorization.type = "None" on the exact same connector/server → Cowork connects, discovers tools, and invokes them correctly in chat. So the transport, dynamic discovery (initialize / tools/list / tools/call, Streamable HTTP), and tool schemas are all compatible with Cowork.
  2. The same OAuth client registration (referenceId) and the same MCP server, used by a declarative agent in M365 Copilot chat, work end-to-end: the OAuth consent succeeds and tool calls arrive at the server bearing a valid Entra v2 access token (aud = the API app, azp = the client app, scp = access_as_user, correct issuer). The server validates it and returns live data.

What fails ❌

With authorization.type = "OAuthPluginVault" in Cowork:

  1. In Sources & Skills, the connector appears and "Connect" / sign-in completes successfully (Entra consent succeeds — no AADSTS error).
  2. Skills load in chat.
  3. When the user asks something that triggers a connector tool, Cowork responds with a message like "I'm unable to reach the connector — it isn't responding in this session."
  4. Server-side during the failure: the connect/validation phase reaches the server, but chat-time tool invocations do not arrive at the server as authenticated calls. (The server logs every request, including unauthenticated ones, which it correctly rejects with 401 while EnforceAuth = true. During the chat-time failure, no valid authenticated tool call is received.)

What I've ruled out

  • MCP transport / discovery — Cowork's own docs state it uses Streamable HTTP with dynamic discovery; my server supports initialize / tools/list / tools/call, and a Microsoft Copilot client (the declarative agent) completes full sessions against it.
  • Tool schema completeness — tools expose full JSON inputSchema; the None-auth connector invokes them fine.
  • The OAuth registration itself — it mints valid per-user v2 tokens that my server accepts; verified by the declarative agent working with the identical referenceId.
  • Redirect URIs / consent — the OAuth/consent step in Cowork succeeds; there is no AADSTS failure in Entra sign-in logs at connect time.
  • Server availability / auth enforcement — server is up; anonymous requests are correctly 401 with EnforceAuth = true; the None-auth path only works when enforcement is disabled.

Conclusion / the question

Everything points to a Cowork-side issue in the OAuthPluginVault flow: the connector authenticates at connect time, but the acquired token is not bound to / sent on chat-time MCP tool calls, so the server never receives an authenticated request and the tool call fails.

  • Is this a known limitation/bug in the current Cowork (Frontier) preview for third-party remote MCP connectors using OAuthPluginVault?
  • Is there any additional manifest, registration, or scope configuration required for Cowork specifically (vs. a declarative agent) to carry the user token into tool calls?
  • If it's a known preview gap, is there an ETA or a supported interim pattern for per-user authenticated custom MCP connectors in Cowork (i.e., something other than None, which is anonymous and unacceptable for production data)?

Minimal repro

  1. Stand up a remote MCP server (Streamable HTTP) that requires an Entra bearer token.
  2. Register an OAuth client (TDP, "Any Microsoft 365 Organization") for it.
  3. Package a Cowork plugin with one agentConnectors → remoteMcpServer using OAuthPluginVault + that referenceId. Sideload.
  4. Connect the connector in Sources & Skills (consent succeeds), then ask chat to use a tool → fails; server receives no authenticated tool call.
  5. Switch the same connector to authorization.type = "None" (and allow anonymous on the server) → works. Use the same referenceId in a declarative agent in M365 Copilot chat → works.

 

Microsoft Copilot | Microsoft 365 Copilot | Development

1 answer

Sort by: Most helpful
  1. AI answer

    2026-06-13T14:09:39.4033333+00:00

    In the available documentation, Cowork (Frontier) supports MCP plugins with OAuthPluginVault and ApiKeyPluginVault, configured via agentConnectors with a referenceId that points to credentials stored in Microsoft’s secure vault. However, there is no additional Cowork-specific configuration documented beyond:

    • Using authorization.type = "OAuthPluginVault" in remoteMcpServer.
    • Ensuring the referenceId is the OAuth configuration registered in Teams Developer Portal / Agents Toolkit with usage set to Any Microsoft 365 Organization.
    • Using Streamable HTTP, JSON-RPC 2.0, and the standard MCP lifecycle (initialize, tools/list, tools/call).

    The context explicitly confirms:

    • Cowork performs dynamic tool discovery for MCP servers and supports OAuthPluginVault and ApiKeyPluginVault for MCP auth, configured via agentConnectors with a referenceId from Teams Dev Center.
    • For OAuthPluginVault, the referenceId is the OAuth client registration ID created when registering an OAuth client with Agents Toolkit, and usage must be Any Microsoft 365 Organization so the plugin works across tenants.
    • No extra scopes, manifest fields, or Cowork-only flags are documented for propagating the user token into MCP tool calls beyond this.

    There is also no documented limitation or bug note in the Cowork or MCP plugin docs that would explain a behavior where:

    • OAuth consent succeeds for the connector, but
    • Cowork does not send an authenticated call to the MCP server at tool invocation time.

    Given that:

    • The same MCP server and OAuth configuration work with a declarative agent in Microsoft 365 Copilot chat.
    • Cowork is explicitly documented as a Frontier preview feature, with the caveat that preview features may have restricted functionality and are subject to change.

    The scenario aligns with an undocumented preview limitation or defect in Cowork’s handling of OAuthPluginVault for remote MCP servers rather than a missing configuration step that can be fixed from the manifest side.

    From the provided material, there is no alternative, documented pattern for per-user OAuth to a custom MCP server in Cowork beyond OAuthPluginVault on remoteMcpServer. The only other supported auth types are None and ApiKeyPluginVault, and the guidance is to prefer OAuth for enterprise scenarios.

    Actionable next steps based on the context:

    1. Confirm that the OAuth client registration used by referenceId is created with usage set to Any Microsoft 365 Organization, as required for cross-tenant plugins.
    2. Confirm that the MCP connector is declared using agentConnectorstoolSource.remoteMcpServer with authorization.type = "OAuthPluginVault" and that the referenceId matches the OAuth configuration in Teams Developer Portal / Agents Toolkit.
    3. Treat the remaining behavior as a Frontier preview issue and open a support case with Microsoft, referencing that:
      • OAuthPluginVault is documented as supported for MCP in Cowork.
      • The same OAuth configuration works in a declarative agent.
      • Cowork is not sending authenticated tool calls despite successful consent.

    There is no documented ETA or workaround in the provided content for achieving per-user authenticated custom MCP connectors in Cowork other than using the standard OAuthPluginVault path, so escalation to Microsoft support is required.


    References:

    AI-generated content may be incorrect. Read our transparency notes for more information.

    Was this answer helpful?

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.