编辑
2025-04-01
我当开发
00

目录

1. 叨叨
2. 引用
3. 核心类 McpEndpointRouteBuilderExtensions
4. 工具类
5. 注册

DotNetMCP SSE实践


1. 叨叨

MCP测试SSE模式

来自公众号 十分钟入门MCPServer , 其实用不了十分钟

这次的核心库是 ModelContextProtocol ,就是官方的库

上次的库MCPSharp还没有支持SSE

图片.png

2. 引用

新建API项目,引用库

<ItemGroup> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /> <PackageReference Include="ModelContextProtocol" Version="0.1.0-preview.2" /> <PackageReference Include="Flurl" Version="4.0.0" /> <PackageReference Include="Flurl.Http" Version="4.0.2" /> </ItemGroup>

3. 核心类 McpEndpointRouteBuilderExtensions

就是开启 /sse

using Microsoft.Extensions.Options; using ModelContextProtocol.Protocol.Messages; using ModelContextProtocol.Protocol.Transport; using ModelContextProtocol.Server; using ModelContextProtocol.Utils.Json; namespace WebSSE { public static class McpEndpointRouteBuilderExtensions { public static IEndpointConventionBuilder MapMcpSse(this IEndpointRouteBuilder endpoints) { IMcpServer? server = null; SseResponseStreamTransport? transport = null; var loggerFactory = endpoints.ServiceProvider.GetRequiredService<ILoggerFactory>(); var mcpServerOptions = endpoints.ServiceProvider.GetRequiredService<IOptions<McpServerOptions>>(); var routeGroup = endpoints.MapGroup(""); routeGroup.MapGet("/sse", async (HttpResponse response, CancellationToken requestAborted) => { await using var localTransport = transport = new SseResponseStreamTransport(response.Body); await using var localServer = server = McpServerFactory.Create(transport, mcpServerOptions.Value, loggerFactory, endpoints.ServiceProvider); await localServer.StartAsync(requestAborted); response.Headers.ContentType = "text/event-stream"; response.Headers.CacheControl = "no-cache"; try { await transport.RunAsync(requestAborted); } catch (OperationCanceledException) when (requestAborted.IsCancellationRequested) { // RequestAborted always triggers when the client disconnects before a complete response body is written, // but this is how SSE connections are typically closed. } }); routeGroup.MapPost("/message", async context => { if (transport is null) { await Results.BadRequest("Connect to the /sse endpoint before sending messages.").ExecuteAsync(context); return; } var message = await context.Request.ReadFromJsonAsync<IJsonRpcMessage>(McpJsonUtilities.DefaultOptions, context.RequestAborted); if (message is null) { await Results.BadRequest("No message in request body.").ExecuteAsync(context); return; } await transport.OnMessageReceivedAsync(message, context.RequestAborted); context.Response.StatusCode = StatusCodes.Status202Accepted; await context.Response.WriteAsync("Accepted"); }); return routeGroup; } } }

4. 工具类

把之前的工具类放上

using Flurl.Http; using ModelContextProtocol.Server; using System.ComponentModel; namespace WebSSE.Tools { [McpServerToolType] public static class ERPCost { [McpServerTool("get-cost-bycode"), Description("通过物料编号得到核价")] public static string GetCostByCode( IMcpServer thisServer, [Description("物料编号")] string code) { var response = "http://localhost/api/CRM/GetCostByCode" .WithHeader("accept", "*/*") .WithHeader("Content-Type", "application/json-patch+json") .PostJsonAsync(new { GUID = "B02C2304120019", hasCode = "", data = new { CostCode = code, } }) .GetAwaiter().GetResult(); // 处理响应 var responseString = response.GetStringAsync().GetAwaiter().GetResult(); var dis = @"Code 1 表示成功 ,非1表示有错误 Message ""成功"" 或 其他错误消息 MB001 品号 MB002 品名 MB003 规格 MB004 单位 CostUnitCost 当前成本(该物料在该账套的最近核价含税) HasNoCost 1表示BOM中有价格为0的物料,0表示没有价格为0的物料 "; return responseString + dis; } } }

注意这里的 类的声明McpServerToolType 和 方法声明McpServerTool

5. 注册

注册工具

builder.Services.AddMcpServer().WithToolsFromAssembly(); app.MapMcpSse();

启动就行了

图片.png

图片.png

图片.png

这样就可以部署到docker进行远程调用了

图片.png

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:没想好

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!