Model Context Protocol (MCP) 完全指南
引言
想象这样一个场景:你的 AI 助手需要访问公司内部数据库、文件系统、第三方 API、代码仓库…传统做法需要为每个数据源编写独立的集成代码,维护成本极高。
Model Context Protocol (MCP) 正是为了解决这个问题而生——一个标准化的协议,让 AI 应用能够以统一的方式访问任何外部数据源和工具。
本文将深入讲解 MCP 的架构、实现方式和最佳实践,助你构建真正"能连接万物"的 AI 应用。
什么是 MCP?
核心定义
Model Context Protocol 是一个开放的、基于 JSON-RPC 2.0 的标准化协议,旨在实现 AI 应用与外部数据源/工具之间的无缝集成。
graph LR
A[AI 应用] -->|MCP 协议| B[MCP Server]
B --> C[(数据库)]
B --> D[文件系统]
B --> E[REST API]
B --> F[Git 仓库]
style A fill:#4CAF50
style B fill:#2196F3
传统集成 vs MCP
传统方式的痛点:
flowchart LR
AI[AI 应用] --> |自定义代码 1| DB[(数据库)]
AI --> |自定义代码 2| API[REST API]
AI --> |自定义代码 3| Files[文件系统]
AI --> |自定义代码 4| Git[Git 仓库]
style AI fill:#FF5252
❌ 每个数据源都需要专门的集成代码
❌ 缺乏标准,维护成本高
❌ 重复造轮子,代码难以复用
❌ 切换数据源需要重写代码
MCP 方式的优势:
flowchart LR
AI[AI 应用] -->|标准 MCP 协议| S1[MCP Server<br/>数据库]
AI -->|标准 MCP 协议| S2[MCP Server<br/>文件系统]
AI -->|标准 MCP 协议| S3[MCP Server<br/>Git]
style AI fill:#4CAF50
✅ 统一接口:所有数据源使用相同的协议
✅ 开箱即用:社区提供大量现成的 MCP Server
✅ 即插即拔:添加/移除数据源只需修改配置
✅ 跨语言支持:Server 可用任何语言实现
MCP 架构详解
三大核心组件
graph TB
subgraph "AI 应用端"
A[MCP Client]
end
subgraph "传输层"
T[Transport<br/>StdIO / HTTP / WebSocket]
end
subgraph "数据/工具端"
S[MCP Server]
S1[Resources<br/>资源提供]
S2[Tools<br/>工具执行]
S3[Prompts<br/>提示模板]
end
A <-->|JSON-RPC 2.0| T
T <-->|JSON-RPC 2.0| S
S --> S1
S --> S2
S --> S3
style A fill:#4CAF50
style S fill:#2196F3
style T fill:#FF9800
1. MCP Client(客户端)
职责:AI 应用侧的代理,负责发起请求和处理响应。
using Microsoft.Extensions.AI.Agents.Mcp;
// 创建 MCP 客户端
var mcpClient = new McpClient(new StdioTransport(
command: "node",
args: new[] { "path/to/mcp-server.js" }
));
// 连接到 Server
await mcpClient.ConnectAsync();
// 查询 Server 的能力
var capabilities = await mcpClient.GetServerCapabilitiesAsync();
Console.WriteLine($"Server 支持的功能: {string.Join(", ", capabilities)}");
2. Transport(传输层)
职责:定义 Client 和 Server 之间的通信方式。
传输方式
说明
适用场景
StdIO
标准输入/输出
本地进程通信(最常用)
HTTP/SSE
HTTP + Server-Sent Events
远程服务、Web 应用
WebSocket
双向通信
实时交互场景
// StdIO Transport(本地进程)
var transport = new StdioTransport("node", new[] { "server.js" });
// HTTP Transport(远程服务)
var transport = new HttpTransport("https://api.example.com/mcp");
// 自定义 Transport
public class CustomTransport : IMcpTransport
{
public async Task SendAsync(JsonRpcMessage message) { ... }
public async Task<JsonRpcMessage> ReceiveAsync() { ... }
}
3. MCP Server(服务端)
职责:暴露数据和工具供 AI 应用使用。
核心能力模型:
能力
说明
示例
Resources
提供只读数据
文件内容、数据库记录、API 响应
Tools
执行操作
文件写入、数据库更新、发送邮件
Prompts
提供提示模板
预定义的对话模板
Sampling
请求 LLM 生成
Server 请求 Client 调用 LLM
Logging
日志记录
调试和审计
MCP 握手流程(Initialize)
Client 和 Server 建立连接时的协商过程:
sequenceDiagram
participant C as MCP Client
participant S as MCP Server
C->>S: Initialize Request<br/>{clientInfo, capabilities}
Note over S: 验证版本兼容性<br/>记录 Client 能力
S-->>C: Initialize Response<br/>{serverInfo, capabilities}
Note over C: 记录 Server 能力<br/>确认可用功能
C->>S: Initialized Notification
Note over S: 连接已就绪
Note over C,S: 可以开始正常通信
示例代码:
// Client 发起握手
var initRequest = new InitializeRequest
{
ProtocolVersion = "2024-11-05",
ClientInfo = new ClientInfo
{
Name = "MyAIApp",
Version = "1.0.0"
},
Capabilities = new ClientCapabilities
{
Roots = new RootsCapability { ListChanged = true },
Sampling = new SamplingCapability() // 支持 Sampling
}
};
var initResponse = await mcpClient.SendRequestAsync<InitializeResponse>(
"initialize",
initRequest
);
// 检查 Server 能力
if (initResponse.Capabilities.Tools != null)
{
Console.WriteLine("Server 支持 Tools 能力");
}
if (initResponse.Capabilities.Resources != null)
{
Console.WriteLine("Server 支持 Resources 能力");
}
// 发送 initialized 通知
await mcpClient.SendNotificationAsync("notifications/initialized");
核心能力深入解析
能力 1:Resources(资源)
用途:提供只读数据,如文件内容、数据库查询结果等。
Server 端实现
using Microsoft.Extensions.AI.Agents.Mcp;
public class FileSystemMcpServer : McpServer
{
protected override Task<ListResourcesResponse> HandleListResourcesAsync(
ListResourcesRequest request)
{
var resources = new[]
{
new Resource
{
Uri = "file:///docs/readme.md",
Name = "README 文档",
Description = "项目说明文档",
MimeType = "text/markdown"
},
new Resource
{
Uri = "file:///data/users.json",
Name = "用户数据",
MimeType = "application/json"
}
};
return Task.FromResult(new ListResourcesResponse { Resources = resources });
}
protected override async Task<ReadResourceResponse> HandleReadResourceAsync(
ReadResourceRequest request)
{
// 根据 URI 读取资源内容
var uri = new Uri(request.Uri);
var filePath = uri.LocalPath;
if (!File.Exists(filePath))
{
throw new McpException($"文件不存在: {filePath}");
}
var content = await File.ReadAllTextAsync(filePath);
return new ReadResourceResponse
{
Contents = new[]
{
new ResourceContent
{
Uri = request.Uri,
MimeType = "text/plain",
Text = content
}
}
};
}
}
Client 端使用
// 列出所有资源
var resourcesResponse = await mcpClient.ListResourcesAsync();
foreach (var resource in resourcesResponse.Resources)
{
Console.WriteLine($"资源: {resource.Name} ({resource.Uri})");
}
// 读取特定资源
var readResponse = await mcpClient.ReadResourceAsync("file:///docs/readme.md");
var content = readResponse.Contents[0].Text;
Console.WriteLine($"文件内容: {content}");
能力 2:Tools(工具)
用途:执行操作,如文件写入、数据库更新、API 调用等。
Server 端实现
public class DatabaseMcpServer : McpServer
{
private readonly IDbConnection _db;
protected override Task<ListToolsResponse> HandleListToolsAsync(
ListToolsRequest request)
{
var tools = new[]
{
new Tool
{
Name = "query_users",
Description = "查询用户列表",
InputSchema = new
{
type = "object",
properties = new
{
limit = new { type = "integer", description = "返回数量" },
offset = new { type = "integer", description = "偏移量" }
}
}
},
new Tool
{
Name = "create_user",
Description = "创建新用户",
InputSchema = new
{
type = "object",
properties = new
{
name = new { type = "string", description = "用户名" },
email = new { type = "string", description = "邮箱" }
},
required = new[] { "name", "email" }
}
}
};
return Task.FromResult(new ListToolsResponse { Tools = tools });
}
protected override async Task<CallToolResponse> HandleCallToolAsync(
CallToolRequest request)
{
switch (request.Name)
{
case "query_users":
var limit = request.Arguments["limit"].GetInt32();
var offset = request.Arguments["offset"].GetInt32();
var users = await _db.QueryAsync<User>(
"SELECT * FROM Users LIMIT @Limit OFFSET @Offset",
new { Limit = limit, Offset = offset }
);
return new CallToolResponse
{
Content = new[]
{
new ToolContent
{
Type = "text",
Text = JsonSerializer.Serialize(users)
}
}
};
case "create_user":
var name = request.Arguments["name"].GetString();
var email = request.Arguments["email"].GetString();
await _db.ExecuteAsync(
"INSERT INTO Users (Name, Email) VALUES (@Name, @Email)",
new { Name = name, Email = email }
);
return new CallToolResponse
{
Content = new[]
{
new ToolContent
{
Type = "text",
Text = $"用户 {name} 创建成功"
}
}
};
default:
throw new McpException($"未知工具: {request.Name}");
}
}
}
Client 端使用
// 列出所有工具
var toolsResponse = await mcpClient.ListToolsAsync();
foreach (var tool in toolsResponse.Tools)
{
Console.WriteLine($"工具: {tool.Name} - {tool.Description}");
}
// 调用工具
var callResponse = await mcpClient.CallToolAsync(new CallToolRequest
{
Name = "query_users",
Arguments = new Dictionary<string, object>
{
["limit"] = 10,
["offset"] = 0
}
});
var result = callResponse.Content[0].Text;
Console.WriteLine($"查询结果: {result}");
能力 3:Prompts(提示模板)
用途:提供预定义的提示词模板。
Server 端实现
public class PromptLibraryMcpServer : McpServer
{
protected override Task<ListPromptsResponse> HandleListPromptsAsync(
ListPromptsRequest request)
{
var prompts = new[]
{
new Prompt
{
Name = "code_review",
Description = "代码审查模板",
Arguments = new[]
{
new PromptArgument
{
Name = "code",
Description = "要审查的代码",
Required = true
},
new PromptArgument
{
Name = "language",
Description = "编程语言",
Required = false
}
}
}
};
return Task.FromResult(new ListPromptsResponse { Prompts = prompts });
}
protected override Task<GetPromptResponse> HandleGetPromptAsync(
GetPromptRequest request)
{
if (request.Name == "code_review")
{
var code = request.Arguments["code"];
var language = request.Arguments.GetValueOrDefault("language", "unknown");
var promptText = $@"请审查以下 {language} 代码:
```{language}
{code}
请分析:
-
潜在的 bug
-
性能问题
-
最佳实践建议";
return Task.FromResult(new GetPromptResponse { Description = "代码审查", Messages = new[] { new PromptMessage { Role = "user", Content = new TextContent { Text = promptText } } } }); } throw new McpException($"未知提示模板: {request.Name}");} }
#### Client 端使用
```csharp
// 获取提示模板
var promptResponse = await mcpClient.GetPromptAsync(new GetPromptRequest
{
Name = "code_review",
Arguments = new Dictionary<string, string>
{
["code"] = "public void ProcessData() { ... }",
["language"] = "csharp"
}
});
// 将模板应用到 AI 对话
var messages = promptResponse.Messages.Select(m =>
new ChatMessage(
m.Role == "user" ? ChatRole.User : ChatRole.System,
m.Content.Text
)
).ToList();
var response = await chatClient.GetResponseAsync(messages);
实战:构建一个完整的 MCP 系统
场景:企业知识库 MCP Server
让我们构建一个能够访问公司文档、数据库和 API 的 MCP Server。
using Microsoft.Extensions.AI.Agents.Mcp;
using Microsoft.Extensions.Logging;
// 1. 定义 MCP Server
public class EnterpriseKnowledgeServer : McpServer
{
private readonly IDocumentRepository _docs;
private readonly IDbConnection _db;
private readonly IApiClient _api;
private readonly ILogger<EnterpriseKnowledgeServer> _logger;
public EnterpriseKnowledgeServer(
IDocumentRepository docs,
IDbConnection db,
IApiClient api,
ILogger<EnterpriseKnowledgeServer> logger)
: base(new McpServerOptions
{
ServerInfo = new ServerInfo
{
Name = "EnterpriseKnowledge",
Version = "1.0.0"
},
Capabilities = new ServerCapabilities
{
Resources = new ResourcesCapability { Subscribe = true },
Tools = new ToolsCapability(),
Prompts = new PromptsCapability(),
Logging = new LoggingCapability()
}
})
{
_docs = docs;
_db = db;
_api = api;
_logger = logger;
}
// 2. 实现 Resources 能力
protected override async Task<ListResourcesResponse> HandleListResourcesAsync(
ListResourcesRequest request)
{
_logger.LogInformation("列出所有资源");
var documents = await _docs.GetAllAsync();
var resources = documents.Select(doc => new Resource
{
Uri = $"doc://{doc.Id}",
Name = doc.Title,
Description = doc.Description,
MimeType = "text/markdown"
}).ToArray();
return new ListResourcesResponse { Resources = resources };
}
protected override async Task<ReadResourceResponse> HandleReadResourceAsync(
ReadResourceRequest request)
{
_logger.LogInformation("读取资源: {Uri}", request.Uri);
// 解析 URI: doc://123
var docId = request.Uri.Replace("doc://", "");
var document = await _docs.GetByIdAsync(docId);
if (document == null)
{
throw new McpException($"文档不存在: {docId}");
}
return new ReadResourceResponse
{
Contents = new[]
{
new ResourceContent
{
Uri = request.Uri,
MimeType = "text/markdown",
Text = document.Content
}
}
};
}
// 3. 实现 Tools 能力
protected override Task<ListToolsResponse> HandleListToolsAsync(
ListToolsRequest request)
{
var tools = new[]
{
new Tool
{
Name = "search_documents",
Description = "搜索企业文档",
InputSchema = new
{
type = "object",
properties = new
{
query = new { type = "string", description = "搜索关键词" },
limit = new { type = "integer", description = "返回数量", default_value = 10 }
},
required = new[] { "query" }
}
},
new Tool
{
Name = "query_database",
Description = "查询企业数据库",
InputSchema = new
{
type = "object",
properties = new
{
table = new { type = "string", description = "表名" },
filters = new { type = "object", description = "过滤条件" }
},
required = new[] { "table" }
}
},
new Tool
{
Name = "call_api",
Description = "调用企业内部 API",
InputSchema = new
{
type = "object",
properties = new
{
endpoint = new { type = "string", description = "API 端点" },
method = new { type = "string", description = "HTTP 方法", enum_values = new[] { "GET", "POST" } },
body = new { type = "object", description = "请求体" }
},
required = new[] { "endpoint", "method" }
}
}
};
return Task.FromResult(new ListToolsResponse { Tools = tools });
}
protected override async Task<CallToolResponse> HandleCallToolAsync(
CallToolRequest request)
{
_logger.LogInformation("调用工具: {ToolName}", request.Name);
try
{
switch (request.Name)
{
case "search_documents":
var query = request.Arguments["query"].GetString();
var limit = request.Arguments.GetValueOrDefault("limit", 10).GetInt32();
var results = await _docs.SearchAsync(query, limit);
return new CallToolResponse
{
Content = new[]
{
new ToolContent
{
Type = "text",
Text = JsonSerializer.Serialize(results, new JsonSerializerOptions
{
WriteIndented = true
})
}
}
};
case "query_database":
var table = request.Arguments["table"].GetString();
var filters = request.Arguments.GetValueOrDefault("filters", new {});
var data = await _db.QueryAsync(BuildSqlQuery(table, filters));
return new CallToolResponse
{
Content = new[]
{
new ToolContent
{
Type = "text",
Text = JsonSerializer.Serialize(data, new JsonSerializerOptions
{
WriteIndented = true
})
}
}
};
case "call_api":
var endpoint = request.Arguments["endpoint"].GetString();
var method = request.Arguments["method"].GetString();
var body = request.Arguments.GetValueOrDefault("body", null);
var apiResponse = await _api.CallAsync(endpoint, method, body);
return new CallToolResponse
{
Content = new[]
{
new ToolContent
{
Type = "text",
Text = apiResponse
}
}
};
default:
throw new McpException($"未知工具: {request.Name}");
}
}
catch (Exception ex)
{
_logger.LogError(ex, "工具执行失败");
return new CallToolResponse
{
IsError = true,
Content = new[]
{
new ToolContent
{
Type = "text",
Text = $"执行失败: {ex.Message}"
}
}
};
}
}
// 4. 实现 Prompts 能力
protected override Task<ListPromptsResponse> HandleListPromptsAsync(
ListPromptsRequest request)
{
var prompts = new[]
{
new Prompt
{
Name = "analyze_document",
Description = "分析企业文档",
Arguments = new[]
{
new PromptArgument { Name = "doc_id", Required = true }
}
},
new Prompt
{
Name = "generate_report",
Description = "生成业务报告",
Arguments = new[]
{
new PromptArgument { Name = "report_type", Required = true },
new PromptArgument { Name = "date_range", Required = false }
}
}
};
return Task.FromResult(new ListPromptsResponse { Prompts = prompts });
}
protected override async Task<GetPromptResponse> HandleGetPromptAsync(
GetPromptRequest request)
{
if (request.Name == "analyze_document")
{
var docId = request.Arguments["doc_id"];
var document = await _docs.GetByIdAsync(docId);
var promptText = $@"请分析以下企业文档:
标题: {document.Title}
内容:
{document.Content}
请提供:
1. 文档摘要
2. 关键要点
3. 相关建议";
return new GetPromptResponse
{
Messages = new[]
{
new PromptMessage
{
Role = "user",
Content = new TextContent { Text = promptText }
}
}
};
}
throw new McpException($"未知提示模板: {request.Name}");
}
private string BuildSqlQuery(string table, object filters)
{
// 简化实现,实际应使用参数化查询
return $"SELECT * FROM {table} WHERE ...";
}
}
// 5. 启动 Server
public class Program
{
public static async Task Main(string[] args)
{
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
// 注册依赖
services.AddSingleton<IDocumentRepository, DocumentRepository>();
services.AddSingleton<IDbConnection, SqlConnection>();
services.AddSingleton<IApiClient, HttpApiClient>();
// 注册 MCP Server
services.AddSingleton<EnterpriseKnowledgeServer>();
})
.Build();
var server = host.Services.GetRequiredService<EnterpriseKnowledgeServer>();
// 使用 StdIO Transport
var transport = new StdioTransport();
await server.RunAsync(transport);
}
}
Client 端使用
using Microsoft.Extensions.AI;
using Microsoft.Extensions.AI.Agents.Mcp;
// 1. 连接到 MCP Server
var mcpClient = new McpClient(new StdioTransport(
command: "dotnet",
args: new[] { "run", "--project", "EnterpriseKnowledgeServer" }
));
await mcpClient.ConnectAsync();
// 2. 将 MCP Tools 转换为 AI Functions
var tools = await mcpClient.GetToolsAsAIFunctionsAsync();
// 3. 创建 AI 客户端
IChatClient chatClient = new OpenAIClient(...)
.AsChatClient("gpt-4")
.UseFunctionInvocation(); // 自动执行函数调用
// 4. 配置选项
var options = new ChatOptions
{
Tools = tools,
ToolMode = ChatToolMode.Auto
};
// 5. 执行对话
var messages = new List<ChatMessage>
{
new(ChatRole.System, "你是企业知识助手,可以访问公司文档、数据库和 API"),
new(ChatRole.User, "搜索关于'产品路线图'的文档")
};
var response = await chatClient.GetResponseAsync(messages, options);
Console.WriteLine(response.Text);
// AI 会自动调用 search_documents 工具,并整合结果返回
高级特性
1. Resources 订阅(Subscribe)
当资源更新时主动通知 Client:
// Server 端
protected override Task HandleResourceSubscribeAsync(
ResourceSubscribeRequest request)
{
_logger.LogInformation("订阅资源: {Uri}", request.Uri);
// 监听资源变化
_docs.OnChanged += async (sender, doc) =>
{
if ($"doc://{doc.Id}" == request.Uri)
{
await SendNotificationAsync("notifications/resources/updated", new
{
uri = request.Uri
});
}
};
return Task.CompletedTask;
}
// Client 端
mcpClient.OnResourceUpdated += async (uri) =>
{
Console.WriteLine($"资源已更新: {uri}");
// 重新读取资源
var content = await mcpClient.ReadResourceAsync(uri);
Console.WriteLine($"新内容: {content}");
};
await mcpClient.SubscribeToResourceAsync("doc://123");
2. Sampling(请求 LLM)
Server 可以请求 Client 调用 LLM:
// Server 端
protected override async Task<SamplingResult> HandleSamplingRequestAsync(
SamplingRequest request)
{
// Server 请求 Client 的 LLM 生成内容
var response = await RequestSamplingAsync(new CreateMessageRequest
{
Messages = new[]
{
new SamplingMessage
{
Role = "user",
Content = new TextContent { Text = "总结这段文本..." }
}
},
MaxTokens = 500
});
return response;
}
// Client 端(自动处理)
mcpClient.OnSamplingRequest += async (request) =>
{
// 使用 AI 客户端处理
var messages = request.Messages.Select(m =>
new ChatMessage(ChatRole.User, m.Content.Text)
).ToList();
var response = await chatClient.GetResponseAsync(messages, new ChatOptions
{
MaxOutputTokens = request.MaxTokens
});
return new SamplingResult
{
Content = new TextContent { Text = response.Text }
};
};
3. 自定义 Transport
实现 HTTP Transport 支持远程 MCP Server:
using System.Net.Http;
using System.Net.Http.Json;
public class HttpMcpTransport : IMcpTransport
{
private readonly HttpClient _httpClient;
private readonly string _endpoint;
public HttpMcpTransport(string endpoint)
{
_httpClient = new HttpClient();
_endpoint = endpoint;
}
public async Task SendAsync(JsonRpcMessage message)
{
var response = await _httpClient.PostAsJsonAsync(
_endpoint,
message
);
response.EnsureSuccessStatusCode();
}
public async Task<JsonRpcMessage> ReceiveAsync()
{
// 使用 Server-Sent Events (SSE) 接收消息
using var request = new HttpRequestMessage(HttpMethod.Get, $"{_endpoint}/events");
request.Headers.Accept.Add(new("text/event-stream"));
using var response = await _httpClient.SendAsync(
request,
HttpCompletionOption.ResponseHeadersRead
);
var stream = await response.Content.ReadAsStreamAsync();
// 解析 SSE 消息...
return await JsonSerializer.DeserializeAsync<JsonRpcMessage>(stream);
}
}
// 使用
var transport = new HttpMcpTransport("https://mcp.example.com");
var mcpClient = new McpClient(transport);
最佳实践
1. 错误处理
// Server 端
protected override async Task<CallToolResponse> HandleCallToolAsync(
CallToolRequest request)
{
try
{
// 执行工具逻辑
var result = await ExecuteToolAsync(request);
return new CallToolResponse
{
Content = new[] { new ToolContent { Text = result } }
};
}
catch (ValidationException ex)
{
// 参数验证错误
_logger.LogWarning(ex, "参数验证失败");
return new CallToolResponse
{
IsError = true,
Content = new[]
{
new ToolContent
{
Type = "text",
Text = $"参数错误: {ex.Message}"
}
}
};
}
catch (Exception ex)
{
// 系统错误
_logger.LogError(ex, "工具执行异常");
return new CallToolResponse
{
IsError = true,
Content = new[]
{
new ToolContent
{
Type = "text",
Text = "系统错误,请稍后重试"
}
}
};
}
}
// Client 端
var response = await mcpClient.CallToolAsync(request);
if (response.IsError)
{
Console.WriteLine($"工具调用失败: {response.Content[0].Text}");
}
2. 性能优化:缓存
public class CachedMcpServer : McpServer
{
private readonly IMemoryCache _cache;
protected override async Task<ReadResourceResponse> HandleReadResourceAsync(
ReadResourceRequest request)
{
var cacheKey = $"resource:{request.Uri}";
// 检查缓存
if (_cache.TryGetValue(cacheKey, out ReadResourceResponse? cached))
{
_logger.LogInformation("缓存命中: {Uri}", request.Uri);
return cached!;
}
// 读取资源
var response = await base.HandleReadResourceAsync(request);
// 缓存 5 分钟
_cache.Set(cacheKey, response, TimeSpan.FromMinutes(5));
return response;
}
}
3. 安全性:权限控制
public class SecureMcpServer : McpServer
{
private readonly IAuthorizationService _authService;
protected override async Task<CallToolResponse> HandleCallToolAsync(
CallToolRequest request)
{
// 从请求中提取用户信息(可通过自定义 Header 传递)
var userId = GetUserIdFromContext();
// 检查权限
if (!await _authService.HasPermissionAsync(userId, $"tool:{request.Name}"))
{
return new CallToolResponse
{
IsError = true,
Content = new[]
{
new ToolContent
{
Type = "text",
Text = "权限不足"
}
}
};
}
// 执行工具
return await base.HandleCallToolAsync(request);
}
}
4. 日志和审计
public class AuditedMcpServer : McpServer
{
private readonly IAuditLogger _auditLogger;
protected override async Task<CallToolResponse> HandleCallToolAsync(
CallToolRequest request)
{
var userId = GetUserIdFromContext();
var startTime = DateTime.UtcNow;
try
{
var response = await base.HandleCallToolAsync(request);
// 记录审计日志
await _auditLogger.LogAsync(new AuditEntry
{
UserId = userId,
Action = "ToolCall",
ToolName = request.Name,
Arguments = request.Arguments,
Success = !response.IsError,
Duration = DateTime.UtcNow - startTime
});
return response;
}
catch (Exception ex)
{
await _auditLogger.LogAsync(new AuditEntry
{
UserId = userId,
Action = "ToolCall",
ToolName = request.Name,
Success = false,
Error = ex.Message
});
throw;
}
}
}
总结
MCP 协议的核心价值:
✅ 统一接口:标准化的 JSON-RPC 2.0 协议
✅ 灵活扩展:Resources、Tools、Prompts 等多种能力模型
✅ 即插即用:社区生态丰富,开箱即用
✅ 跨语言支持:Server 可用任何语言实现
✅ 生产级特性:权限控制、错误处理、日志审计
记住:MCP = 统一的协议 + 标准的能力模型 + 灵活的传输层 + 丰富的生态