MCP客户端开发指南
理解和开发模型上下文协议(MCP)客户端的全面指南。
目录
什么是MCP?
这 模型上下文协议(MCP) 是一个开放标准,可实现人工智能系统(如LLM)与各种数据源和工具之间的无缝集成。把它想象成 USB-C用于人工智能应用 -标准化LLM访问上下文方式的通用连接器。
关键利益
- 🔌 单一集成点:通过一个协议连接到任何MCP服务器
- 🔄 LLM独立:在不更改集成的情况下在LLM提供商之间切换
- 🔒 内置安全:人工审批模式和安全检查
- 📦 可扩展性:易于集成新工具和数据源
- 🎯 模块化:LLM逻辑与数据访问逻辑的分离
核心架构
MCP遵循 客户端-服务器体系结构 使用这些组件:
┌─────────────────────────────────────────────────┐
│ MCP Host (Your AI Application) │
│ ┌──────────────────────────────────────────┐ │
│ │ MCP Client 1 ←→ MCP Server (Weather) │ │
│ │ MCP Client 2 ←→ MCP Server (Database) │ │
│ │ MCP Client 3 ←→ MCP Server (Files) │ │
│ └──────────────────────────────────────────┘ │
└─────────────────────────────────────────────────┘组件
- MCP主机:用户与之交互的应用程序(Claude Desktop、IDE、自定义应用程序)
- MCP客户端:在主机应用程序中运行,维护 1:1连接 与服务器
- MCP服务器:通过标准API公开功能的轻量级程序
重要:每个MCP客户端与一台服务器保持1:1连接。对于多个服务器,运行多个客户端实例。
客户开发人员的关键概念
1.三个核心图元
您的客户必须处理三种类型的功能:
🛠️ 工具(模型控制)
LLM可以调用以执行操作的函数。
{
"name": "get_weather",
"description": "Get current weather for a location",
"inputSchema": {
"type": "object",
"properties": {
"location": { "type": "string" }
}
}
}📄 资源(应用程序控制)
LLM可以读取的数据源(类似于REST GET端点)。
{
"uri": "file:///project/README.md",
"name": "Project README",
"mimeType": "text/markdown"
}💬 提示(用户控制)
指导LLM交互的预定义模板。
{
"name": "code_review",
"description": "Review code for best practices",
"arguments": [
{
"name": "code",
"description": "Code to review",
"required": true
}
]
}2.运输机制
选择客户的沟通方式:
- 标准 (标准输入/输出):适用于同一台机器上的本地服务器
- HTTP与SSE:对于远程服务器(服务器发送事件)
- 可流式传输的HTTP:较新的运输方式
3.连接流程
┌──────────┐ ┌──────────┐
│ Client │ │ Server │
└────┬─────┘ └────┬─────┘
│ │
│ 1. Initialize (Handshake) │
│ ────────────────────────────────────>│
│ │
│ │
│ tools = await client.ListToolsAsync();
// Resources
var resources = await client.ListResourcesAsync();
// Prompts
var prompts = await client.ListPromptsAsync();3.工具执行
var result = await client.CallToolAsync(
"toolName",
new Dictionary() { ["arg"] = "value" },
cancellationToken
);4.协议细节
- ✅ JSON-RPC消息格式
- ✅ 请求/响应序列化
- ✅ 协议版本协商
- ✅ 错误处理(McpException)
5.微软。扩展。人工智能集成
// McpClientTool inherits from AIFunction
IList tools = await client.ListToolsAsync();
IChatClient chatClient = ...;
// Tools are ALREADY in LLM-compatible format!
var response = await chatClient.GetResponseAsync(
"your prompt",
new() { Tools = [.. tools] }
);❌ 你必须实施什么
1.LLM函数调用翻译
// YOU parse LLM responses
var llmResponse = await chatClient.GetResponseAsync(...);
foreach (var update in llmResponse)
{
if (update is FunctionCallUpdate functionCall)
{
// Extract tool name and arguments
string toolName = functionCall.Name;
var args = functionCall.Arguments;
// Call MCP
var result = await client.CallToolAsync(toolName, args, ct);
}
}2.会话上下文管理
List conversationHistory = [];
// Add user message
conversationHistory.Add(new ChatMessage(ChatRole.User, userInput));
// Get LLM response with tool calls
var response = await chatClient.GetResponseAsync(
conversationHistory,
new() { Tools = tools }
);
// YOU must manage:
// - Assistant's tool call messages
// - Tool execution results
// - Conversation continuation
conversationHistory.Add(new ChatMessage(ChatRole.Assistant, response));
conversationHistory.Add(new ChatMessage(ChatRole.Tool, toolResult));3.安全与审批
async Task GetUserApproval(string toolName, object args)
{
Console.WriteLine($"⚠️ Allow execution of {toolName}?");
Console.WriteLine($" Arguments: {JsonSerializer.Serialize(args)}");
Console.Write(" Approve? (y/n): ");
return Console.ReadLine()?.ToLower() == "y";
}
if (await GetUserApproval(toolName, args))
{
await client.CallToolAsync(toolName, args, ct);
}4.编排循环
// YOU implement the agentic conversation loop
var messages = new List();
while (!done)
{
// 1. Get user input
var userInput = Console.ReadLine();
messages.Add(new(ChatRole.User, userInput));
// 2. Send to LLM with tools
var updates = new List();
await foreach (var update in chatClient.GetStreamingResponseAsync(
messages, new() { Tools = tools }))
{
// 3. Check for tool calls in updates
// 4. Execute via MCP client
// 5. Add results to messages
updates.Add(update);
}
// 6. Continue conversation
messages.AddMessages(updates);
}5.多服务器管理
// Each client = ONE server
// YOU route tool calls to the correct client
var weatherClient = await McpClient.CreateAsync(weatherTransport);
var dbClient = await McpClient.CreateAsync(dbTransport);
var fileClient = await McpClient.CreateAsync(fileTransport);
// Map tool names to clients
var toolRouter = new Dictionary
{
["get_weather"] = weatherClient,
["query_database"] = dbClient,
["read_file"] = fileClient
};
// Route tool calls
var targetClient = toolRouter[toolName];
await targetClient.CallToolAsync(toolName, args, ct);入门指南
先决条件
# For C# development
dotnet add package ModelContextProtocol --prerelease
dotnet add package Microsoft.Extensions.AI --prerelease基本客户端示例
using ModelContextProtocol.Client;
using Microsoft.Extensions.AI;
// 1. Create transport (connects to MCP server)
var transport = new StdioClientTransport(new StdioClientTransportOptions
{
Name = "Everything",
Command = "npx",
Arguments = ["-y", "@modelcontextprotocol/server-everything"],
});
// 2. Create and connect client
var mcpClient = await McpClient.CreateAsync(transport);
// 3. Discover available tools
IList tools = await mcpClient.ListToolsAsync();
Console.WriteLine("Available tools:");
foreach (var tool in tools)
{
Console.WriteLine($" - {tool.Name}: {tool.Description}");
}
// 4. Setup LLM client (example with Azure OpenAI)
IChatClient chatClient = new ChatClientBuilder(
new AzureOpenAIClient(endpoint, credential)
.GetChatClient("gpt-4o")
.AsIChatClient())
.UseFunctionInvocation()
.Build();
// 5. Conversational loop
var messages = new List();
while (true)
{
Console.Write("You: ");
messages.Add(new(ChatRole.User, Console.ReadLine()));
var updates = new List();
await foreach (var update in chatClient.GetStreamingResponseAsync(
messages, new() { Tools = [.. tools] }))
{
Console.Write(update);
updates.Add(update);
}
Console.WriteLine();
messages.AddMessages(updates);
}测试您的客户
使用MCP检查器进行调试:
npx @modelcontextprotocol/inspector或者使用“everything”服务器进行测试:
npx -y @modelcontextprotocol/server-everythingSDK选项
| 语言 | 包 | 描述 |
|---|---|---|
C ModelContextProtocol | 微软维护的官方SDK | |
| Types/JavaScript | @modelcontextprotocol/sdk | TypeScript官方SDK |
python mcp | 官方Python SDK | |
| Java | 社区 | 社区维护 |
| Rust | 社区 | 社区维护 |
架构图
┌─────────────────────────────────────────────────────────────┐
│ Your Application │
│ (MCP Host) │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Your Code │ │
│ │ • Conversation loop │ │
│ │ • Security/approval logic │ │
│ │ • Tool call routing │ │
│ │ • Context management │ │
│ └───────────────┬────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────▼────────────────────────────────────────┐ │
│ │ Microsoft.Extensions.AI │ │
│ │ • IChatClient abstraction │ │
│ │ • Function invocation handling │ │
│ └───────────────┬────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────▼────────────────────────────────────────┐ │
│ │ MCP C# SDK (McpClient) │ │
│ │ ✅ Connection management │ │
│ │ ✅ Capability discovery │ │
│ │ ✅ Tool execution │ │
│ │ ✅ Protocol handling │ │
│ └───────────────┬────────────────────────────────────────┘ │
└──────────────────┼──────────────────────────────────────────┘
│
┌─────────┴─────────┐
│ stdio/HTTP/SSE │ (Transport Layer)
└─────────┬─────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│ Server │ │ Server │ │ Server │
│ 1 │ │ 2 │ │ 3 │
└────────┘ └────────┘ └────────┘关键要点
- MCP是协议,而不是实施
- 每个客户端连接到一个服务器 (1:1关系)
- SDK处理协议细节,您构建编排
- 工具无缝集成 微软。扩展。人工智能
- 您控制安全、路由和对话流
