使用.NET实现自带思考的Tool 并且提供MCP服务
下面我们将使用.net实现自带思考的Tool并且提供mcp streamable http供其他AI客户端使用
创建项目
创建WebAPI项目并且命名MarkAgent.Host
名称,然后安装下面的包
<ItemGroup> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.6" /> <PackageReference Include="ModelContextProtocol" Version="0.3.0-preview.3" /> <PackageReference Include="ModelContextProtocol.AspNetCore" Version="0.3.0-preview.3" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.0.2" /> <PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="9.0.6" /> <PackageReference Include="Scalar.AspNetCore" Version="1.1.0" /> </ItemGroup>
创建Prompts.cs文件,这里我们会提供系统需要的所有提示词:
namespace MarkAgent.Host; public class Prompts { public const string DeepThinkingPrompt = """ Use this tool to engage in deep, structured thinking about complex problems, user requirements, or challenging decisions. This tool helps you process information systematically and provides your thought process back to enhance understanding and decision-making. ## When to Use This Tool Use this tool proactively in these scenarios: 1. **Complex Problem Analysis** - When facing multi-faceted problems that require careful consideration 2. **Requirement Clarification** - When user requests are ambiguous and need deeper exploration 3. **Decision Points** - When multiple approaches exist and you need to evaluate trade-offs 4. **Architecture Planning** - When designing systems or making technical decisions 5. **Risk Assessment** - When considering potential issues or complications 6. **Learning from Context** - When analyzing existing code or systems to understand patterns ## Core Thinking Principles 1. **Question Assumptions** - Challenge initial interpretations and explore alternatives 2. **Break Down Complexity** - Decompose complex problems into manageable components 3. **Consider Multiple Perspectives** - Look at problems from different angles 4. **Evaluate Trade-offs** - Weigh pros and cons of different approaches 5. **Anticipate Consequences** - Think through potential implications and side effects 6. **Build on Context** - Use existing knowledge and patterns to inform decisions ## Thinking Process Structure Your thought process should follow this pattern: 1. **Initial Understanding** - What is the core problem or requirement? 2. **Context Analysis** - What relevant information do we have? 3. **Assumption Identification** - What assumptions am I making? 4. **Alternative Exploration** - What other approaches could work? 5. **Trade-off Evaluation** - What are the pros and cons of each option? 6. **Decision Rationale** - Why is this the best approach? 7. **Implementation Considerations** - What practical factors matter? 8. **Risk Assessment** - What could go wrong and how to mitigate? ## Examples of Deep Thinking Scenarios <example> User: "I want to add real-time notifications to my app" Thought Process: - Initial Understanding: User wants real-time notifications, but what type? Push notifications, in-app notifications, or both? - Context Analysis: Need to examine existing tech stack, user base size, notification frequency - Assumptions: Assuming they want both types, but should clarify the specific use cases - Alternatives: WebSockets, Server-Sent Events, Push API, third-party services - Trade-offs: WebSockets offer full duplex but require more infrastructure; SSE is simpler but one-way - Decision: Recommend starting with requirements clarification, then suggest appropriate technology based on their specific needs - Implementation: Consider scalability, reliability, user preferences - Risks: Notification fatigue, performance impact, complexity overhead </example> <example> User: "This code is running slowly, can you help optimize it?" Thought Process: - Initial Understanding: Performance issue exists, but need to identify bottlenecks - Context Analysis: Need to examine the code, understand data volumes, usage patterns - Assumptions: Assuming it's algorithmic complexity, but could be I/O, memory, or network - Alternatives: Algorithm optimization, caching, database indexing, parallel processing - Trade-offs: Code complexity vs performance gains, memory usage vs speed - Decision: Profile first to identify actual bottlenecks before optimizing - Implementation: Measure performance, implement targeted optimizations - Risks: Premature optimization, breaking existing functionality, over-engineering </example> ## Guidelines for Effective Thinking 1. **Be Thorough** - Don't rush to conclusions; explore the problem space fully 2. **Stay Objective** - Consider evidence and logic over preferences 3. **Embrace Uncertainty** - It's okay to acknowledge when you need more information 4. **Think Practically** - Consider real-world constraints and limitations 5. **Document Reasoning** - Clearly explain your thought process and rationale 6. **Iterate and Refine** - Be prepared to revise your thinking as new information emerges The goal is to provide well-reasoned, thoughtful analysis that leads to better outcomes and helps others understand complex problems more clearly. """; public const string SequentialThinkingPrompt = """ A detailed tool for dynamic and reflective problem-solving through thoughts. This tool helps analyze problems through a flexible thinking process that can adapt and evolve. Each thought can build on, question, or revise previous insights as understanding deepens. When to use this tool: - Breaking down complex problems into steps - Planning and design with room for revision - Analysis that might need course correction - Problems where the full scope might not be clear initially - Problems that require a multi-step solution - Tasks that need to maintain context over multiple steps - Situations where irrelevant information needs to be filtered out You should: 1. Start with an initial estimate of needed thoughts, but be ready to adjust 2. Feel free to question or revise previous thoughts 3. Don't hesitate to add more thoughts if needed, even at the "end" 4. Express uncertainty when present 5. Mark thoughts that revise previous thinking or branch into new paths 6. Ignore information that is irrelevant to the current step 7. Generate a solution hypothesis when appropriate 8. Verify the hypothesis based on the Chain of Thought steps 9. Repeat the process until satisfied with the solution 10. Provide a single, ideally correct answer as the final output 11. Only set next_thought_needed to false when truly done and a satisfactory answer is reached """; public const string MentalModelPrompt = """ A tool for applying structured mental models to problem-solving. Supports various mental models including: - First Principles Thinking - Opportunity Cost Analysis - Error Propagation Understanding - Rubber Duck Debugging - Pareto Principle - Occam's Razor Each model provides a systematic approach to breaking down and solving problems. """; }
注意,上面的提示词非常的重要,它会影响Tool的输入效果
然后我们继续,创建ThoughtData.cs
public class ThoughtData { public string thought { get; set; } = string.Empty; public int thoughtNumber { get; set; } public int totalThoughts { get; set; } public bool isRevision { get; set; } = false; public int? revisesThought { get; set; } public int? branchFromThought { get; set; } public string? branchId { get; set; } public bool needsMoreThoughts { get; set; } = false; public bool nextThoughtNeeded { get; set; } = true; }
创建MentalModelData.cs
public class MentalModelData { public MentalModelName ModelName { get; set; } public string Problem { get; set; } = string.Empty; public string[] Steps { get; set; } = []; public string Reasoning { get; set; } = string.Empty; public string Conclusion { get; set; } = string.Empty; } public enum MentalModelName { FirstPrinciples, OpportunityCost, ErrorPropagation, RubberDuck, ParetoPrinciple, OccamsRazor, }
现在我们可以创建AgentTool.cs
核心的MCP Tool代码了,这个代码会整合AI入的内容然后反馈给AI。
using System.ComponentModel; using System.Text; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; using MarkAgent.Host.Domain.Entities; using MarkAgent.Host.Domain.Events; using MarkAgent.Host.Domain.Services; using MarkAgent.Host.Tools.Models; using ModelContextProtocol.Server; namespace MarkAgent.Host.Tools; [McpServerToolType] public class AgentTools(IStatisticsChannelService statisticsChannel) { [McpServerTool, Description(Prompts.MentalModelPrompt)] public MentalModelData MentalModel(MentalModelName model, string problem, string[] steps, string reasoning, string conclusion) { // 验证必需字段 if (string.IsNullOrEmpty(problem)) { throw new ArgumentException("Invalid problem: must be a string", nameof(problem)); } // 处理可选字段并应用默认值 var processedSteps = steps ?? []; var processedReasoning = !string.IsNullOrEmpty(reasoning) ? reasoning : ""; var processedConclusion = !string.IsNullOrEmpty(conclusion) ? conclusion : ""; // 创建并返回 MentalModelData 对象 return new MentalModelData { ModelName = model, Problem = problem, Steps = processedSteps, Reasoning = processedReasoning, Conclusion = processedConclusion }; } [McpServerTool, Description(Prompts.SequentialThinkingPrompt)] public ThoughtData SequentialThinking( string thought, int thoughtNumber, int totalThoughts, bool nextThoughtNeeded, bool isRevision, int revisesThought, int branchFromThought, string branchId, bool needsMoreThoughts) { // 验证必需字段 if (string.IsNullOrEmpty(thought)) { throw new ArgumentException("Invalid thought: must be a string", nameof(thought)); } if (thoughtNumber <= 0) { throw new ArgumentException("Invalid thoughtNumber: must be a positive number", nameof(thoughtNumber)); } if (totalThoughts <= 0) { throw new ArgumentException("Invalid totalThoughts: must be a positive number", nameof(totalThoughts)); } // 处理可选字段 - 在 C# 中这些已经是参数,但我们可以添加额外的验证逻辑 var processedIsRevision = isRevision; var processedRevisesThought = revisesThought > 0 ? (int?)revisesThought : null; var processedBranchFromThought = branchFromThought > 0 ? (int?)branchFromThought : null; var processedBranchId = !string.IsNullOrEmpty(branchId) ? branchId : null; var processedNeedsMoreThoughts = needsMoreThoughts; // 创建并返回 ThoughtData 对象 return new ThoughtData { thought = thought, thoughtNumber = thoughtNumber, totalThoughts = totalThoughts, nextThoughtNeeded = nextThoughtNeeded, isRevision = processedIsRevision, revisesThought = processedRevisesThought, branchFromThought = processedBranchFromThought, branchId = processedBranchId, needsMoreThoughts = processedNeedsMoreThoughts }; } [McpServerTool, Description(Prompts.DeepThinkingPrompt)] public string DeepThinking( IMcpServer mcpServer, [Description( "Your structured thought process about the problem, following the thinking framework provided in the tool description. This should be a detailed analysis that explores the problem from multiple angles.")] string thought) { var startTime = DateTime.UtcNow; string? errorMessage = null; bool isSuccess = true; try { // 设置控制台编码支持UTF-8 Console.OutputEncoding = Encoding.UTF8; Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Cyan; Console.ResetColor(); Console.WriteLine("─".PadRight(50, '─')); Console.WriteLine(thought); Console.WriteLine("─".PadRight(50, '─')); Console.WriteLine(); // 构建返回给大模型的消息 var responseMessage = BuildThoughtResponseMessage(thought); return responseMessage; } catch (Exception ex) { isSuccess = false; errorMessage = ex.Message; throw; } finally { // 记录工具使用统计 var endTime = DateTime.UtcNow; var inputJson = JsonSerializer.Serialize(new { thought }); var sessionId = mcpServer.SessionId; // 异步记录统计,不阻塞主流程 _ = Task.Run(async () => { try { var toolUsageEvent = new ToolUsageEvent { ToolName = "DeepThinking", SessionId = sessionId ?? string.Empty, StartTime = startTime, EndTime = endTime, IsSuccess = isSuccess, ErrorMessage = errorMessage, InputSize = Encoding.UTF8.GetByteCount(inputJson), OutputSize = 0, // 输出大小在返回时计算 ParametersJson = inputJson }; await statisticsChannel.WriteToolUsageEventAsync(toolUsageEvent); } catch { // 忽略统计记录错误,不影响主功能 } }); } } private string BuildThoughtResponseMessage(string thought) { var sb = new StringBuilder(); sb.AppendLine( "Deep thinking process completed successfully. Your structured analysis has been recorded and will inform future decision-making."); sb.AppendLine(); sb.AppendLine("<system-reminder>"); sb.AppendLine( "The AI has engaged in deep thinking about the current problem/requirement. Key insights from this analysis:"); sb.AppendLine(); sb.AppendLine($"Thought Process: {thought}"); sb.AppendLine(); sb.AppendLine( "Use these insights to make more informed decisions and provide better solutions. The thinking process should guide your approach to the problem."); sb.AppendLine("</system-reminder>"); return sb.ToString(); } }
在这里我们提供了三个Tool,三个不同的Tool,面向思考方式思考处理都不太一样,然后我们现在对外提供MCP服务,打开我们的Program.cs
var builder = WebApplication.CreateBuilder(args); builder.Services .AddMcpServer((options => { options.ServerInfo = new Implementation { Name = "MarkAgent", Version = typeof(Program).Assembly.GetName().Version?.ToString() ?? "1.0.0", Title = "MarkAgent MCP Server", }; })) .WithHttpTransport(options => { options.RunSessionHandler += async (context, serverOptions, arg3) => { try { // 获取客户端信息 var ipAddress = context.Connection.RemoteIpAddress?.ToString(); var userAgent = context.Request.Headers.UserAgent.ToString(); // 获取请求客户端信息 var clientName = userAgent; var clientVersion = serverOptions?.ClientInfo?.Version ?? "0.0.0"; var clientTitle = userAgent; // 生成会话ID var sessionId = serverOptions.SessionId; Console.WriteLine($"Client connected: {clientName} v{clientVersion} (Session: {sessionId[..8]}...)"); await serverOptions.RunAsync(); } catch (Exception ex) { // 记录错误但不影响连接 Console.WriteLine($"❌ Error recording client connection: {ex.Message}"); } }; }) .WithTools<AgentTools>(); var app = builder.Build(); app.MapMcp("/mcp"); await app.RunAsync();
上面的代码就将我们的Tool加入到了MCP Server当中了,现在我们只需要启动服务即可,然后打开cherry Studio
进行测试。
进行链接测试
打开软件以后找到设置,然后点击MCP设置
然后填充json配置
案例:
{ "mcpServers": { "agent": { "url": "http://localhost:5157/mcp", "type":"streamableHttp" } } }
然后点击确定,然后进入MCP并且打开工具我们可以看到下面几个Function
然后现在回到对话界面,并且选择我们添加的MCP
然后我们进行测试发送下面内容,然后测试效果如图
帮我写一篇c#入门教程,请深入思考
当然如果您觉得麻烦我们提供了在线的MCP服务下面是接入的教程:
Trae接入MarkAgent
打开Trae,然后点击功能管理,在右上角
然后点击MCP,在点击手动添加
然后将下面的内容粘贴进去然后点击确认:
{ "mcpServers": { "agent": { "url": "http://localhost:5157/mcp", "type":"streamableHttp" } } }
添加完成以后一共提供了四个Tool,前面三个是用于优化思考,最后面的是Todo 跟Claude Code中的Todo功能是完全一样的,提示词是直接使用了Claude Code的提示词,通过这些Tool,您可以体验非一般的AI!
Copilot接入MarkAgent
先打开您的项目根目录,然后在根目录创建.vscode
目录,然后在目录下在创建mcp.json
文件,并且填充下面的内容,然后我们现在打开VSCode。
{ "servers": { "todo": { "url": "https://agent.mark-chat.chat/mcp", "type": "http" } } }
点击输入框下面的工具
然后下面提供了我们的Tool了
我们只需要对话即可,在需要的时候AI会自行调用Tool,下面开始您的AI之旅。
Rider接入MarkAgent
打开Rider,然后打开Github Copilot
然后点击输入框左边的工具
然后点击Add MCP Tools
然后填充下面的配置:
{ "servers": { "todo": { "url": "https://agent.mark-chat.chat/mcp", "type": "http" } } }
然后关闭文件,然后我们就可以看到输入框左边显示如图效果:
技术交流群
.NET AI学习交流群 加我备注.NET AI
qq:961090189
这一切,似未曾拥有