Microsoft 365 Copilot
Microsoft 365 Copilot
FabrCore.Services.Microsoft365Copilot is a server addon that surfaces your FabrCore agents in Microsoft 365 Copilot, Teams, and other Azure Bot Service channels as a custom engine agent. It hosts the /api/messages endpoint with the Microsoft 365 Agents SDK, validates channel and Entra identity, maps each Microsoft 365 user to a FabrCore principal, provisions their agent on first contact, and streams replies back—without any changes to FabrCore.Host or your agents.
Your FabrCore Host can run in Azure, on-premises, or any cloud. Azure Bot Service only needs a public HTTPS route to /api/messages—a dev tunnel works for development.
How It Works
Microsoft 365 Copilot / Teams
│ Activity (JWT from Azure Bot Service)
▼
POST /api/messages ──► Copilot bridge (Agents SDK)
│ │ Entra user ──► FabrCore principal handle
│ │ ensure agent ──► per-user agent instance
│ ▼
◄── streamed reply ── your [AgentAlias] agent on the Orleans silo
Each Microsoft 365 user maps to their own FabrCore principal (Entra object id by default), and each principal gets its own agent instance with isolated chat history, state, and ACL boundary—the same model the rest of FabrCore uses.
Setup
Add the package to your FabrCore server project and wire up two lines:
builder.AddFabrCoreServer(new FabrCoreServerOptions
{
AdditionalAssemblies = [typeof(MyAgent).Assembly]
});
builder.AddMicrosoft365Copilot(); // after AddFabrCoreServer
var app = builder.Build();
app.UseFabrCoreServer();
app.UseMicrosoft365Copilot(); // maps POST /api/messages
app.Run();
Configuration lives in one Microsoft365Copilot section of fabrcore.json (or appsettings.json):
{
"Microsoft365Copilot": {
"TenantId": "<entra-tenant-id>",
"ClientId": "<bot-app-registration-client-id>",
"ClientSecret": "<bot-app-registration-secret>",
"Agent": {
"AgentType": "chat-agent",
"SystemPrompt": "You are a helpful assistant.",
"Models": "default"
},
"Manifest": {
"Name": "My FabrCore Agent",
"Description": "Answers questions using my FabrCore agents.",
"PublicHostName": "myagents.contoso.com"
}
}
}
Agent:AgentType is any [AgentAlias] registered through AdditionalAssemblies. The addon translates this one section into the Microsoft 365 Agents SDK configuration it needs (Connections, ConnectionsMap, AgentApplication); if you define any of those sections natively, the addon leaves them untouched.
On the Azure side you create one Entra app registration and one Azure Bot resource with the Teams channel enabled (Teams also carries Microsoft 365 Copilot traffic), pointing its messaging endpoint at your host. Supported credential types: client secret, certificate, managed identity, federated credentials, and workload identity.
Identity and Principals
Teams and Copilot stamp the user's Entra identity on every activity. The addon turns it into a FabrCore principal handle:
Principal:Strategy | Handle | Use when |
|---|---|---|
EntraObjectId (default) | Entra object id | Single-tenant bots |
TenantAndObjectId | {tenantId}-{objectId} | Multi-tenant bots |
UserPrincipalName | UPN from the SSO token | Readable handles; needs user authorization |
ChannelUserId | {channelId}-{userId} | Dev/test channels only |
Every bridged message also carries the raw identity and conversation context in AgentMessage.Args (Microsoft365Copilot:AadObjectId, :TenantId, :UserName, :ConversationId, and more), and AgentMessage.Channel is "m365copilot" so agents can branch on ingress source. Custom mapping is one interface: register your own ICopilotPrincipalResolver before AddMicrosoft365Copilot().
Set Agent:SharedAgentHandle (for example system:helpdesk) to route every user to one agent instead of per-user instances. Cross-principal messaging is subject to ACL—grant agent.message.allow to the mapped principals.
User SSO and On-Behalf-Of
No sign-in prompt is needed for identity—that comes from the channel. Configure user authorization when agents must call Microsoft Graph or your APIs as the user. Handlers use the Microsoft 365 Agents SDK schema and are forwarded verbatim:
"UserAuthorization": {
"PassUserTokenToAgent": true,
"Handlers": {
"graph": {
"Settings": {
"AzureBotOAuthConnectionName": "<oauth-connection-name>",
"OBOConnectionName": "ServiceConnection",
"OBOScopes": ["https://graph.microsoft.com/.default"]
}
}
}
}
With PassUserTokenToAgent enabled, agents and plugins receive the user's access token as Args["Microsoft365Copilot:UserToken"]. The token then flows through FabrCore messaging and any configured monitors—enable it deliberately and scope OBO minimally. The generated app manifest automatically gains the webApplicationInfo SSO section when handlers are configured.
App Package Generation
The addon generates the Microsoft 365 app manifest and uploadable package entirely from configuration—no hand-authored manifest. In Development (or with Manifest:EnableAppPackageEndpoint: true):
| Endpoint | Returns |
|---|---|
GET /m365copilot/manifest.json | Manifest (schema v1.22) with copilotAgents.customEngineAgents bound to your bot, conversation starters, and SSO metadata when configured |
GET /m365copilot/appPackage.zip | Manifest + icons, ready to upload in Teams or the Microsoft 365 admin center |
Upload for yourself via Teams (Apps → Manage your apps → Upload a custom app) or org-wide via the Microsoft 365 admin center (Settings → Integrated apps). The agent then appears in the Copilot Agents rail (Microsoft 365 Copilot license required) and answers 1:1 Teams chat.
Streaming and Responses
On streaming-capable channels the addon sends a configurable informative update ("Working on it..."), keeps a typing indicator running while the FabrCore agent works, and delivers the reply through the channel streaming protocol with the AI generated label. Feedback (thumbs up/down) buttons are available via Streaming:EnableFeedbackLoop. Other channels receive a single buffered reply.
Local Development
Test the full bridge with no Azure resources using the Microsoft 365 Agents Playground:
"Microsoft365Copilot": {
"TokenValidation": { "Enabled": false },
"Agent": { "AgentType": "chat-agent" }
}
With token validation off the endpoint accepts anonymous requests (a startup warning reminds you), and users map by channel user id. To exercise the real Teams/Copilot channels from a dev box, host a dev tunnel and point the Azure Bot's messaging endpoint at it.
Production Checklist
- Keep
TokenValidation:Enabledtrue(the default) anywhere internet-reachable. Inbound channel JWTs validate under a dedicated scheme that never interferes with your host's own authentication. - Register a durable Agents SDK
IStorage(for example blob storage) beforeAddMicrosoft365Copilot()when scaling out or using SSO—sign-in and turn state default to memory. - Prefer certificate or managed-identity credentials over client secrets, and keep
fabrcore.jsonout of source control. - Use SQL or Azure Orleans clustering so per-user agents survive restarts.
- Replace the generated placeholder icons via
Manifest:ColorIconPath/Manifest:OutlineIconPathbefore publishing.
The FabrCore repository ships a fabrcore-microsoft365copilot skill under docs/skills with copyable configuration templates, an Azure provisioning script, and deep-dive references for Azure Bot setup and Entra SSO.