mcpField
M
m365-agents-dotnet

m365-agents-dotnet

github.com/sickn33Agent 工作流48.7k41 次安装今天更新
代码仓库

关于 m365-agents-dotnet

m365-agents-dotnet 是面向 .NET 开发者的 Skill,指导使用 Microsoft.Agents SDK 构建 Microsoft 365、Teams 和 Copilot Studio Agent,涵盖 ASP.NET Core 托管、路由与 MSAL 身份验证模式。

主要功能

  1. 01ASP.NET Core Agent 托管
  2. 02AgentApplication 路由指导
  3. 03MSAL 身份验证模式
  4. 04Copilot Studio 客户端集成
  5. 05生产环境安全实践

适用场景

  1. 01使用 .NET 构建 Microsoft 365 Agent
  2. 02通过 ASP.NET Core 托管 Agent
  3. 03将 .NET 应用连接到 Copilot Studio

MCP 相关

该 Skill 指引开发者使用 microsoft-docs MCP 核实当前 SDK API;它本身未描述 MCP 服务。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill m365-agents-dotnet

安装后在 Claude Code 中输入/m365-agents-dotnet确认已加载。

详细介绍

支持材料可用性

本目录副本包含以下内联指导,但不包含下列支持文件路径。这些是外部前置条件,并非随附文件:

  • <support-root>/references/acceptance-criteria.md

使用依赖这些路径的步骤前,请索取原始支持材料或现有安装;本目录未提供经验证的下载来源。根据该安装解析每个路径,检查其内容,并核实适用的许可证和执行前置条件。在所需文件存在之前,不要运行命令,也不要声称已按照所引用的流程操作。不要伪造缺失的脚本,也不要将同名的不相关文件视为等效文件。此处已完整记录的独立步骤,可在用户授权范围内继续;任何依赖步骤均应报告为不可用。

Microsoft 365 Agents SDK (.NET)

概述

使用 Microsoft.Agents SDK、ASP.NET Core 托管、Agent 路由和基于 MSAL 的身份验证,为 Microsoft 365、Teams 和 Copilot Studio 构建企业级 Agent。

实施前

  • 使用 microsoft-docs MCP 验证 AddAgent、AgentApplication 和身份验证选项的最新 API。
  • 在 NuGet 中确认计划使用的 Microsoft.Agents.* 包版本。

安装

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

配置(appsettings.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": ""
  }
}

核心工作流:ASP.NET Core Agent 主机

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 路由

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 直连引擎客户端

用于令牌获取的 DelegatingHandler(交互式流程)
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);
    }
}
使用 CopilotClient 的控制台主机
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);
}

最佳实践

  1. 使用 AgentApplication 子类集中处理路由和错误。
  2. MemoryStorage 仅用于开发;生产环境请使用持久化存储。
  3. 在生产环境中启用 TokenValidation,并要求对 /api/messages 进行授权。
  4. 将身份验证密钥保存在配置提供程序中(Key Vault、托管标识、环境变量)。
  5. 复用来自 IHttpClientFactory 的 HttpClient,并缓存 MSAL 令牌。
  6. 优先使用异步处理程序,并向 SDK 调用传递 CancellationToken。

参考文件

文件内容
references/acceptance-criteria.md导入路径、托管管道、Copilot Studio 客户端模式、反模式

参考链接

资源URL
Microsoft 365 Agents SDKhttps://learn.microsoft.com/en-us/microsoft-365/agents-sdk/
AddAgent APIhttps://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.hosting.aspnetcore.servicecollectionextensions.addagent?view=m365-agents-sdk
AgentApplication APIhttps://learn.microsoft.com/en-us/dotnet/api/microsoft.agents.builder.app.agentapplication?view=m365-agents-sdk
身份验证配置选项https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/microsoft-authentication-library-configuration-options
Copilot Studio 集成https://learn.microsoft.com/en-us/microsoft-365/agents-sdk/integrate-with-mcs
GitHub 示例https://github.com/microsoft/agents

适用场景

此技能适用于执行概述中描述的工作流或操作。

限制

  • 仅当任务明确符合上述范围时,才使用此技能。
  • 不要将输出视为环境特定验证、测试或专家审查的替代品。
  • 如果缺少必需输入、权限、安全边界或成功标准,请停止并请求澄清。

评论

支持 Markdown