使用模型上下文协议构建AI代理:C#实现全面指南

本文详细介绍了如何使用模型上下文协议和C#构建AI代理,涵盖协议架构、C# SDK实现、安全考虑和实际部署方案,为开发者提供构建可扩展AI系统的完整技术指南。

模型上下文协议基础

大型语言模型的快速发展永久改变了人工智能应用,因为它提供了自然语言理解和生成能力以及推理能力。LLMs的显著成就仍然有限,因为这些模型无法访问实时数据源,也无法利用外部计算工具。这种隔离阻止了这些模型提供最新信息,同时限制了它们与演进系统协同工作和执行超越文本生成任务的能力。

当前解决这个问题的方法要求开发者为每个数据源或工具构建应用特定的连接,导致系统复杂、难以管理、扩展和跨AI应用标准化。实施通信协议、认证机制和数据转换逻辑需要为每个集成项目进行定制工作,导致高开发成本和系统间的不兼容性。

模型上下文协议通过其通用接口标准解决了这些问题,使AI系统能够连接外部资源。MCP基于一个基本原则:创建一个"AI应用USB-C端口",使任何符合MCP标准的客户端能够连接到任何符合MCP标准的服务器,而无需了解实现细节。

通过其标准化方法,MCP为构建AI代理的开发人员提供了基本优势。所有连接的API表面保持统一,简化了多个数据源的集成。标准化的认证和授权机制增强了安全性和隐私控制。标准化使得可以创建组织和各种AI应用都可以使用的可重用组件。

MCP提供的优势超越了功能可用性。MCP的标准协议使得能够发展一个生态系统,使AI代理能够在各种工具和数据源之间切换,而不会丢失上下文和状态。构建复杂的AI代理——需要执行复杂的多步骤任务——需要与多个系统交互的能力。

C#编程语言和.NET生态系统代表了开发基于MCP的AI代理的最佳基础。官方C# SDK是Anthropic和Microsoft的协作项目,利用了现代.NET应用的依赖注入、托管和配置能力。这种集成使开发人员能够创建可扩展、可维护的AI代理,这些代理可以在各种部署环境中运行,从本地开发机器到基于云的生产环境。

核心组件和能力

MCP系统包含多个基本元素,这些元素共同工作以实现AI系统与外部资源的完整集成。成功开发基于MCP的AI代理需要对这些组件的透彻理解。

资源在MCP中充当主要的数据访问工具。通过资源,服务器可以向AI模型和用户呈现标准化内容和上下文信息。每个资源都有自己独特的URI,支持识别并表示从基本文本文件到复杂结构化信息的内容。资源抽象系统使服务器能够分发数据,而无需客户端了解存储方法或访问协议。

资源向用户提供永久和动态内容。静态资源包含在大部分时间内保持未修改的稳定内容,包括文档和配置文件。第二类资源包括动态内容,这些内容从当前系统数据和外部环境因素产生输出,从而实现实时信息集成。

MCP服务器充当AI系统、实时数据库、API和监控系统之间的数据桥梁,因为它们提供了这种灵活性。

MCP的面向操作组件包括工具,使AI模型能够在连接系统中运行功能和执行操作。工具的定义过程包括完整的模式细节,定义了它们所需的输入参数以及预期的输出结果和行为描述。模式驱动模型使AI模型能够正确理解工具用法,同时保持类型安全和验证。

MCP工具执行机制将系统安全性和用户管理作为其基本设计原则。工具调用必须获得用户的明确许可才能进行,协议允许用户在运行前检查工具使用情况。AI代理可以通过这种方法执行复杂的自动化任务,同时保持对未授权活动的保护。

通过提示,服务器可以显示预构建的通信模板以及AI应用可以使用的工作流模板。资源和工具主要服务于AI模型,而提示通过为任务和查询提供结构化模板来支持人机交互。模板包含可自定义的参数,这些参数从当前上下文中获取值。

通过提示系统,开发人员可以创建可在各种AI应用中使用的可重用交互模式。此功能对于需要建立标准AI交互或为不熟悉最优提示策略的用户创建逐步帮助的组织最为有益。

传输层和通信机制

MCP的传输层为客户端和服务器之间的通信提供了基础,支持多种传输机制以适应不同的部署场景和要求。协议的传输无关设计确保相同的应用逻辑可以在各种通信渠道上工作而无需修改。

标准输入/输出传输代表了MCP实现中最常见的传输机制。这种方法利用了所有操作系统和编程环境中标准输入和输出流的普遍可用性。Stdio传输特别适用于本地开发场景以及MCP服务器作为可由客户端应用启动和管理的单独进程部署的情况。

Stdio传输模型为开发和测试提供了几个优势。它通过标准日志机制支持直接调试,支持简单的进程生命周期管理,并且需要最少的配置。此外,stdio传输自然地提供进程隔离,确保服务器故障不会直接影响客户端应用。

HTTP传输将MCP的范围扩展到分布式系统和基于Web的部署。通过支持标准HTTP协议,MCP服务器可以作为可从任何网络连接客户端访问的Web服务部署。这种传输机制支持诸如服务于多个客户端应用的共享MCP服务器或服务器和客户端在不同环境中操作的基于云的部署等场景。

HTTP传输引入了关于认证、授权和网络安全的额外考虑。MCP的设计通过可扩展的头部机制和对标准HTTP安全实践的支持来适应这些要求。协议还定义了处理HTTP特定关注点(如连接池、超时管理和错误处理)的具体要求。

服务器发送事件传输提供了一种混合方法,结合了基于HTTP通信的优势与实时流能力。SSE传输使服务器能够将更新推送到客户端,而无需持续轮询,使其成为涉及实时数据馈送或长时间运行操作的场景的理想选择。

SSE传输机制对于需要保持对外部条件变化的认识或接收相关事件通知的AI代理特别有价值。这种能力使得能够开发更响应和上下文感知的AI系统,这些系统可以在不需要显式用户干预的情况下对外部变化做出反应。

C# SDK实现和架构

模型上下文协议的官方C# SDK代表了利用.NET生态系统所有功能的完整实现。SDK作为三个独立的包存在,由Anthropic和Microsoft共同开发,以满足不同的应用需求和部署要求。

ModelContextProtocol包作为大多数应用的主要起点。该包包括托管扩展和依赖注入集成以及遵循现代.NET开发标准的高级抽象。该包与Microsoft.Extensions.Hosting框架完美配合,让开发人员通过建立的模式和约定创建MCP服务器和客户端。

ModelContextProtocol.Core包为需要基本依赖项或希望直接执行低级协议操作的应用程序提供了简化版本。该包包括基本的客户端和服务器API以及协议类型定义和传输抽象,但不包括托管和依赖注入功能。SDK支持各种部署场景,因为其设计使得从简单的控制台应用程序到复杂的分布式系统的部署成为可能。

ModelContextProtocol.AspNetCore包为ASP.NET Core应用程序提供基于HTTP的MCP服务器功能。该包包括中间件和路由扩展以及服务器发送事件支持,使MCP服务器能够作为Web服务运行。与ASP.NET Core管道的集成使MCP服务器能够利用框架的内置认证和授权功能以及日志记录和监控功能。

SDK的模块化设计展示了一种经过深思熟虑的SDK开发方法,结合了可用性和适应性。开发人员根据他们的需求选择所需的包,因此他们的应用程序只包含必要的依赖项。这种方法对于云原生环境至关重要,因为它有助于减少资源使用和启动持续时间。

依赖注入和服务配置

C# SDK与Microsoft的依赖注入框架的集成代表了其最重要的架构优势之一。这种集成使开发人员能够利用他们在其他.NET应用中使用的相同模式和实践,减少学习曲线并提高代码可维护性。

SDK提供了与IServiceCollection接口无缝集成的扩展方法,允许MCP服务器和客户端与其他应用服务一起配置。这种方法支持复杂的场景,例如将外部服务注入MCP工具、配置多个传输机制以及实现自定义认证和授权逻辑。服务注册遵循流畅配置模式,使开发人员能够准确指定其MCP服务器应公开哪些功能。

例如,WithToolsFromAssembly()方法使用反射自动发现和注册标有McpServerTool属性的方法,消除了手动注册的需要,同时保持类型安全。依赖注入集成还支持复杂的测试场景。因为MCP工具和资源作为服务注册,它们可以在单元测试期间轻松模拟或替换为测试实现。这种能力对于构建可靠、可测试的AI代理至关重要,这些代理可以独立于其外部依赖进行验证。

传输层实现

C# SDK包括传输功能,为MCP接口提供抽象的通信选项。抽象使相同的应用逻辑能够在多个传输类型上工作而无需修改,从而提供部署和集成灵活性。

Stdio传输实现利用标准输入和输出流(这些流普遍可用)来提供基本但高效的通信系统。SDK处理所有进程管理任务和流缓冲以及错误处理,为开发人员提供直接的接口。

这种传输类型最适合本地开发环境以及包括单独基于进程的MCP服务器部署的场景。

Stdio传输实现提供了错误检测和恢复功能。SDK通过提供特定的错误消息来响应通信错误,同时尝试恢复连接。系统需要健壮,以确保生产就绪,因为可靠性是主要优先事项。

HTTP传输实现使MCP能够在分布式环境以及Web部署中运行。SDK利用ASP.NET Core建立的HTTP处理功能为基于HTTP的MCP服务器开发健壮且可扩展的基础。此实现支持常见的HTTP功能,包括压缩、缓存和连接池。

HTTP传输实现解决了基于Web的AI代理部署带来的特定困难。基于Web的AI应用可以通过跨源资源共享支持连接到MCP服务器,生产部署使用标准HTTP认证机制。实现包括完整的日志记录和监控功能,这些功能与ASP.NET Core的内置可观察性功能集成。

服务器发送事件传输除了基于HTTP通信的优势外,还提供实时流功能。传输方法为需要外部条件监控和相关事件通知能力的AI代理提供特定价值。

C# SDK通过其SSE实现处理长连接复杂性,为开发人员提供简单的编程模型。SDK自动管理连接生命周期,保持平滑的客户端断开连接,并提供向多个连接的客户端广播更新的工具。

实际实现示例

基本MCP服务器实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;

namespace MCPExamples
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = Host.CreateApplicationBuilder(args);
            
            // 配置日志记录到stderr以兼容MCP
            builder.Logging.AddConsole(consoleLogOptions =>
            {
                consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
            });
            
            // 配置MCP服务器与stdio传输和工具发现
            builder.Services
                .AddMcpServer()
                .WithStdioServerTransport()
                .WithToolsFromAssembly();
                
            await builder.Build().RunAsync();
        }
    }
    
    [McpServerToolType]
    public static class BasicTools
    {
        [McpServerTool, Description("将提供的消息回显给客户端")]
        public static string Echo(
            [Description("要回显的消息")] string message)
        {
            return $"Echo: {message}";
        }
        
        [McpServerTool, Description("计算提供文本的长度")]
        public static int TextLength(
            [Description("要测量的文本")] string text)
        {
            return text?.Length ?? 0;
        }
    }
}

这个基本实现演示了几个关键概念。Host.CreateApplicationBuilder()方法创建了一个包含依赖注入、配置和日志记录功能的.NET应用。日志记录配置将输出定向到标准错误,因为标准输出保留用于协议通信。

AddMcpServer()扩展方法启用了MCP服务器功能所需的服务,而WithStdioServerTransport()配置服务器使用标准输入/输出进行通信。我们使用WithToolsFromAssembly()方法。工具发现过程自动找到具有所需属性的工具,因此不需要手动注册。

工具实现展示了如何通过属性公开功能。当一个类收到McpServerToolType属性时,它成为一个MCP工具容器,而各个方法通过McpServerTool属性成为工具。描述属性包含人类可读的文本,帮助AI模型理解工具用法。

具有外部服务集成的高级服务器

大多数复杂的MCP服务器需要连接到外部数据库、服务和API。以下示例显示如何创建一个MCP服务器,该服务器使用依赖注入来访问外部服务,同时保持业务逻辑与MCP特定代码的分离。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Server;
using System.ComponentModel;
using System.Text.Json;

namespace MCPExamples.Advanced
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = Host.CreateApplicationBuilder(args);
            
            // 注册外部服务
            builder.Services.AddHttpClient();
            builder.Services.AddSingleton<IWeatherService, WeatherService>();
            builder.Services.AddSingleton<IDataAnalysisService, DataAnalysisService>();
            
            builder.Services
                .AddMcpServer()
                .WithStdioServerTransport()
                .WithToolsFromAssembly()
                .WithPromptsFromAssembly();
                
            await builder.Build().RunAsync();
        }
    }
    
    [McpServerToolType]
    public static class AdvancedTools
    {
        [McpServerTool, Description("获取指定位置的当前天气信息")]
        public static async Task<string> GetWeather(
            IWeatherService weatherService,
            [Description("要获取天气的位置")] string location)
        {
            var weather = await weatherService.GetWeatherAsync(location);
            return JsonSerializer.Serialize(weather, new JsonSerializerOptions
            { WriteIndented = true });
        }
        
        [McpServerTool, Description("对数值数据执行统计分析")]
        public static async Task<string> AnalyzeData(
            IDataAnalysisService analysisService,
            [Description("要分析的数值数组")] double[] data)
        {
            var analysis = await analysisService.AnalyzeDataAsync(data);
            var report = await analysisService.GenerateReportAsync(analysis);
            return report;
        }
    }
}

高级示例展示了构建生产就绪MCP服务器的基本模式。通过IWeatherService和IDataAnalysisService的外部服务依赖注入实现了MCP特定逻辑与业务逻辑的清晰分离。代码分离支持更好的可测试性和可维护性,并允许业务逻辑在不同上下文之间重用。

外部服务使用接口允许开发人员在单元测试期间通过用模拟实现替换服务来创建复杂的测试场景。这种方法对于创建可靠的AI代理至关重要,这些代理可以在没有外部依赖的情况下证明其功能。

客户端实现和集成模式

MCP客户端使AI应用能够连接并与MCP服务器通信。下面的示例显示如何创建一个能够检测和利用服务器功能的完整MCP客户端。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
using ModelContextProtocol;
using ModelContextProtocol.Client;
using Microsoft.Extensions.AI;
using System.Text.Json;

namespace MCPExamples.Client
{
    public class MCPClientExample
    {
        private IMcpClient? _client;
        
        public async Task<bool> ConnectToServerAsync(string serverCommand, string[] arguments)
        {
            try
            {
                var clientTransport = new StdioClientTransport(new StdioClientTransportOptions
                {
                    Name = "ExampleClient",
                    Command = serverCommand,
                    Arguments = arguments
                });
                
                _client = await McpClientFactory.CreateAsync(clientTransport);
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Failed to connect to server: {ex.Message}");
                return false;
            }
        }
        
        public async Task<string?> ExecuteToolAsync(string toolName, Dictionary<string, object?> arguments)
        {
            if (_client == null) return null;
            
            try
            {
                var result = await _client.CallToolAsync(toolName, arguments, CancellationToken.None);
                var textContent = result.Content.FirstOrDefault(c => c.Type == "text");
                return textContent?.Text;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error executing tool {toolName}: {ex.Message}");
                return null;
            }
        }
    }
}

客户端实现展示了MCP服务器连接和交互的基本模式。StdioClientTransport配置定义了服务器进程启动方法和服务器进程通信协议,而McpClientFactory.CreateAsync()方法处理服务器连接建立和能力协商。

ExecuteToolAsync()的工具执行模式展示了如何启动服务器工具并处理其结果。该方法提供了详细的错误处理,让客户端应用能够正确处理服务器故障和通信问题。

ASP.NET Core HTTP服务器实现

ASP.NET Core包为需要基于Web的部署或与现有Web应用集成的场景提供完整的基于HTTP的MCP服务器支持。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using ModelContextProtocol.AspNetCore;
using ModelContextProtocol.Server;

namespace MCPExamples.AspNetCore
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
            
            // 配置服务
            builder.Services.AddHttpClient();
            builder.Services.AddSingleton<IDocumentService, DocumentService>();
            
            // 配置具有HTTP传输的MCP服务器
            builder.Services
                .AddMcpServer()
                .WithHttpServerTransport()
                .WithToolsFromAssembly();
                
            // 为Web客户端访问添加CORS
            builder.Services.AddCors(options =>
            {
                options.AddDefaultPolicy(policy =>
                {
                    policy.AllowAnyOrigin()
                          .AllowAnyMethod()
                          .AllowAnyHeader();
                });
            });
            
            var app = builder.Build();
            
            app.UseCors();
            app.UseRouting();
            app.MapMcpServer();
            
            app.Run();
        }
    }
}

ASP.NET Core实现展示了MCP服务器如何融入Web应用。WithHttpServerTransport()方法为服务器设置基于HTTP的MCP通信,而MapMcpServer()将必要的端点添加到ASP.NET Core路由系统。

CORS配置允许基于Web的AI应用连接到MCP服务器,从而实现各种客户端实现。此能力是构建在Web浏览器内和其他基于Web的系统中运行的AI代理的关键元素。

安全考虑和最佳实践

安全架构和信任模型

模型上下文协议的设计专门解决了允许AI系统访问外部数据源和执行任意代码所带来的安全风险。协议的安全模型依赖于用户同意和控制,以允许用户维护数据共享和代表他们执行的操作的权限。

安全架构包含多个层,保护用户与AI应用以及外部系统之间信任关系的不同方面。MCP定义了特定的协议级边界,确定哪些责任属于客户端和服务器,同时要求对敏感操作进行显式授权。客户端-服务器架构在AI应用和外部资源之间建立了自然屏障,阻止了对安全控制的未经授权的直接访问。

用户同意机制建立了MCP的基本安全框架。所有工具调用都需要用户授权才能执行,协议定义了客户端在执行前向用户显示工具描述以及参数的常见方法。该方法允许用户在执行前了解每个操作的后果,同时保持对AI代理活动的人工监督。

协议设计在每个阶段都包含了数据隐私保护。主机在向服务器透露用户数据之前需要获得直接用户许可,协议提供了管理数据传输到外部系统的工具。实施的保护在企业环境中起着至关重要的作用,因为它们帮助组织在执

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计