Skip to main content
skill

m365-agents-dotnet — Claude Code skill: what it does, how to install

Guides .NET developers in building multichannel agents for Teams, M365, and Copilot Studio using ASP.NET Core and MSAL authentication.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add microsoft/skills --skill m365-agents-dotnet -a claude-code
Open on GitHub

What m365-agents-dotnet does

This skill supplies architectural patterns and code samples for developing enterprise agents with the Microsoft.Agents SDK in C#. It outlines how to bootstrap an ASP.NET Core host, expose the /api/messages endpoint, and wire in-memory state storage.

Event handling is organized around the AgentApplication class, routing message activities, member arrivals, and turn errors. The skill also documents appsettings.json schemas for tenant validation, Bot Framework connections, and Copilot Studio settings.

Before running the snippets, check package versions directly on NuGet. You also need registered Azure app credentials, specifically a tenant ID and client ID, to complete the authentication setup.

What it helps with

  • scaffold an ASP.NET Core host for Microsoft 365 agent endpoints
  • route incoming conversation activities using AgentApplication
  • configure MSAL authentication and token validation in appsettings.json
  • acquire authorization tokens for Copilot Studio direct-to-engine calls

Example prompts for the agent

  • Set up an ASP.NET Core service with Microsoft Agents SDK authentication and endpoints
  • Create an AgentApplication class that welcomes new members and echoes incoming text
  • Write appsettings.json connection settings for Microsoft 365 agent authentication

How to install m365-agents-dotnet

1Skills CLI (Vercel)

npx skills add microsoft/skills --skill m365-agents-dotnet -a claude-code

2Manually: put the files in place

~/.claude/skills/m365-agents-dotnet/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/m365-agents-dotnet/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about m365-agents-dotnet

How to install m365-agents-dotnet in Claude Code?

Run the command npx skills add microsoft/skills --skill m365-agents-dotnet -a claude-code in your terminal.

What does m365-agents-dotnet do?

It provides scaffolding and setup guidance for building .NET agents targeting Microsoft 365, Teams, and Copilot Studio.

Which NuGet packages does this skill use?

The patterns rely on Microsoft.Agents.Hosting.AspNetCore, Microsoft.Agents.Authentication.Msal, Microsoft.Agents.Storage, and Copilot Studio client packages.

Source text

SKILL.md · MIT
---
name: m365-agents-dotnet
description: |
  Microsoft 365 Agents SDK for .NET. Build multichannel agents for Teams/M365/Copilot Studio with ASP.NET Core hosting, AgentApplication routing, and MSAL-based auth. Triggers: "Microsoft 365 Agents SDK", "Microsoft.Agents", "AddAgentApplicationOptions", "AgentApplication", "AddAgentAspNetAuthentication", "Copilot Studio client", "IAgentHttpAdapter".
license: MIT
metadata:
  author: Microsoft
  version: "1.0.0"
  package: Microsoft.Agents.Hosting.AspNetCore, Microsoft.Agents.Authentication.Msal, Microsoft.Agents.CopilotStudio.Client
---

# Microsoft 365 Agents SDK (.NET)

## Overview

Build enterprise agents for Microsoft 365, Teams, and Copilot Studio using the Microsoft.Agents SDK with ASP.NET Core hosting, agent routing, and MSAL-based authentication.

## Before implementation

- Use the microsoft-docs MCP to verify the latest APIs for AddAgent, AgentApplication, and authentication options.
- Confirm package versions in NuGet for the Microsoft.Agents.\* packages you plan to use.

## Installation

```bash
dotnet add package Microsoft.Agents.Hosting.AspNetCore
dotnet add package Microsoft.Agents.Authentication.Msal
dotnet add package Microsoft.Agents.Storage
dotnet add package Microsoft.Agents.CopilotStudio.Client
dotnet add package Microsoft.Identity.Client.Extensions.Msal
```

## Configuration (appsettings.json)

```json
{
  "TokenValidation": {
    "Enabled": true,
    "Audiences": ["{{ClientId}}"],
    "TenantId": "{{TenantId}}"
  },
  "AgentApplication": {
    "StartTypingTimer": false,
    "RemoveRecipientMention": false,
    "NormalizeMentions": false
  },
  "Connections": {
    "ServiceConnection": {
      "Settings": {
        "AuthType": "ClientSecret",
        "ClientId": "{{ClientId}}",
        "ClientSecret": "{{ClientSecret}}",
        "AuthorityEndpoint": "https://login.microsoftonline.com/{{TenantId}}",
        "Scopes": ["https://api.botframework.com/.default"]
      }
    }
  },
  "ConnectionsMap": [
    {
      "ServiceUrl": "*",
      "Connection": "ServiceConnection"
    }
  ],
  "CopilotStudioClientSettings": {
    "DirectConnectUrl": "",
    "EnvironmentId": "",
    "SchemaName": "",
    "TenantId": "",
    "AppClientId": "",
    "AppClientSecret": ""
  }
}
```

## Core Workflow: ASP.NET Core agent host

```csharp
using Microsoft.Agents.Builder;
using Microsoft.Agents.Hosting.AspNetCore;
using Microsoft.Agents.Storage;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient();
builder.AddAgentApplicationOptions();
builder.AddAgent<MyAgent>();
builder.Services.AddSingleton<IStorage, MemoryStorage>();

builder.Services.AddControllers();
builder.Services.AddAgentAspNetAuthentication(builder.Configuration);

WebApplication app = builder.Build();

app.UseAuthentication();
app.UseAuthorization();

app.MapGet("/", () => "Microsoft Agents SDK Sample");

var incomingRoute = app.MapPost("/api/messages",
    async (HttpRequest request, HttpResponse response, IAgentHttpAdapter adapter, IAgent agent, CancellationToken ct) =>
    {
        await adapter.ProcessAsync(request, response, agent, ct);
    });

if (!app.Environment.IsDevelopment())
{
    incomingRoute.RequireAuthorization();
}
else
{
    app.Urls.Add("http://localhost:3978");
}

app.Run();
```

## AgentApplication routing

```csharp
using Microsoft.Agents.Builder;
using Microsoft.Agents.Builder.App;
using Microsoft.Agents.Builder.State;
using Microsoft.Agents.Core.Models;
using System;
using System.Threading;
using System.Threading.Tasks;

public sealed class MyAgent : AgentApplication
{
    public MyAgent(AgentApplicationOptions options) : base(options)
    {
        OnConversationUpdate(ConversationUpdateEvents.MembersAdded, WelcomeAsync);
        OnActivity(ActivityTypes.Message, OnMessageAsync, rank: RouteRank.Last);
        OnTurnError(OnTurnErrorAsync);
    }

    private static async Task WelcomeAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken ct)
    {
        foreach (ChannelAccount member in turnContext.Activity.MembersAdded)
        {
            if (member.Id != turnContext.Activity.Recipient.Id)
            {
                await turnContext.SendActivityAsync(
                    MessageFactory.Text("Welcome to the agent."),
                    ct);
            }
        }
    }

    private static async Task OnMessageAsync(ITurnContext turnContext, ITurnState turnState, CancellationToken ct)
    {
        await turnContext.SendActivityAsync(
            MessageFactory.Text($"You said: {turnContext.Activity.Text}"),
            ct);
    }

    private static async Task OnTurnErrorAsync(
        ITurnContext turnContext,
        ITurnState turnState,
        Exception exception,
        CancellationToken ct)
    {
        await turnState.Conversation.DeleteStateAsync(turnContext, ct);

        var endOfConversation = Activity.CreateEndOfConversationActivity();
        endOfConversation.Code = EndOfConversationCodes.Error;
        endOfConversation.Text = exception.Message;
        await turnContext.SendActivityAsync(endOfConversation, ct);
    }
}
```

## Copilot Studio direct-to-engine client

### DelegatingHandler for token acquisition (interactive flow)

```csharp
using System.Net.Http.Headers;
using Microsoft.Agents.CopilotStudio.Client;
using Microsoft.Identity.Client;

internal sealed class AddTokenHandler : DelegatingHandler
{
    private readonly SampleConnectionSettings _settings;

    public AddTokenHandler(SampleConnectionSettings settings) : base(new HttpClientHandler())
    {
        _settings = settings;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        if (request.Headers.Authorization is null)
        {
            string[] scopes = [CopilotClient.ScopeFromSettings(_settings)];

            IPublicClientApplication app = PublicClientApplicationBuilder
                .Create(_settings.AppClientId)
                .WithAuthority(AadAuthorityAudience.AzureAdMyOrg)
                .WithTenantId(_settings.TenantId)
                .WithRedirectUri("http://localhost")
                .Build();

            AuthenticationResult authResponse;
            try
            {
                var account = (await app.GetAccountsAsync()).FirstOrDefault();
                authResponse = await app.AcquireTokenSilent(scopes, account).ExecuteAsync(cancellationToken);
            }
            catch (MsalUiRequiredException)
            {
                authResponse = await app.AcquireTokenInteractive(scopes).ExecuteAsync(cancellationToken);
            }

            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResponse.AccessToken);
        }

        return await base.SendAsync(request, cancellationToken);
    }
}
```

### Console host with CopilotClient

```csharp
using Microsoft.Agents.CopilotStudio.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

var settings = new SampleConnectionSettings(
    builder.Configuration.GetSection("CopilotStudioClientSettings"));

builder.Services.AddHttpClient("mcs").ConfigurePrimaryHttpMessageHandler(() =>
{
    return new AddTokenHandler(settings);
});

builder.Services
    .AddSingleton(settings)
    .AddTransient<CopilotClient>(sp =>
    {
        var logger = sp.GetRequiredService<ILoggerFactory>().CreateLogger<CopilotClient>();
        return new CopilotClient(settings, sp.GetRequiredService<IHttpClientFactory>(), logger, "mcs");
    });

IHost host = builder.Build();
var client = host.Services.GetRequiredService<CopilotClient>();

await foreach (var activity in client.StartConversationAsync(emitStartConversationEvent: true))
{
    Console.WriteLine(activity.Type);
}

await foreach (var activity in client.AskQuestionAsync("Hello!", null))
{
    Console.WriteLine(activity.Type);
}
```

## Best Practices

1. Use AgentApplication subclasses to centralize routing and error handling.
2. Use MemoryStorage only for development; use persisted storage in production.
3. Enable TokenValidation in production and require authorization on /api/messages.
4. Keep auth secrets in configuration providers (Key Vault, managed identity, env vars).
5. Reuse HttpClient from IHttpClientFactory and cache MSAL tokens.
6. Prefer async handlers and pass CancellationToken to SDK calls.

## Reference Links

| Resource                   | URL                                                                                                                                        |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Microsoft 365 Agents SDK   | https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/                                                                                |
| AddAgent API               | https://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.hosting.aspnetcore.servicecollectionextensions.addagent?view=m365-agents-sdk |
| AgentApplication API       | https://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.builder.app.agentapplication?view=m365-agents-sdk                            |
| Auth configuration options | https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/microsoft-authentication-library-configuration-options                          |
| Copilot Studio integration | https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/integrate-with-mcs                                                              |
| GitHub samples             | https://github.com/microsoft/agents                                                                                                        |

© Microsoft · MIT · microsoft/skills

Similar skills

All skills for Backend and APIs →

From the same set242

The whole set →
azure-ai-voicelive-py Helps build real-time voice applications in Python using Azure AI Voice Live SDK with bidirectional WebSocket streaming. 1installs azure-ai-language-conversations-py A skill for Conversational Language Understanding with the Python SDK: intent and entity analysis for dialog. Useful when you build NLP features on Azure. 1installs azure-ai-contentunderstanding-py Teaches your coding agent to use the Azure AI Content Understanding Python SDK. Extracts structured markdown, transcripts, and key video frames. 1installs microsoft-azure-webjobs-extensions-authentication-events-dotnet A skill for handling Microsoft Entra ID custom authentication events in .NET: token claims, attribute collection, OTP delivery. 1installs azure-security-keyvault-keys-dotnet A skill for managing Azure Key Vault and Managed HSM keys from .NET: creation, rotation, encryption, signing. Useful when your agent writes C#. 1installs azure-search-documents-dotnet Instructs AI agents on using the Azure.Search.Documents SDK in .NET for full-text, vector, and hybrid search, index management, and document CRUD. 1installs azure-resource-manager-sql-dotnet Manage Azure SQL resources through Azure Resource Manager from .NET. The skill covers provisioning servers and databases, configuring pools and firewall rules, and listing resources. 1installs azure-resource-manager-mysql-dotnet A skill that gives your agent .NET SDK patterns for MySQL Flexible Server on Azure: servers, databases, firewall rules, parameters and backups. 1installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor