MCP客户端入门

客户端是与 MCP 服务器直接通信以请求资源、工具和提示的自定义应用程序或脚本。与使用提供图形界面的检查工具不同,编写自己的客户端可以实现编程和自动化交互。这使开发人员能够将 MCP 功能集成到自己的工作流程中,自动化任务,并构建针对特定需求量身定制的解决方案。

概述

本课程介绍了 Model Context Protocol (MCP) 生态系统中的客户端概念。您将学习如何编写自己的客户端并将其连接到 MCP 服务器。

学习目标

完成本课程后,您将能够:

  • 了解客户端的功能。
  • 编写自己的客户端。
  • 连接并测试客户端与 MCP 服务器,以确保服务器正常工作。

编写客户端需要做什么?

要编写客户端,您需要完成以下步骤:

  • 导入正确的库。您将使用之前相同的库,但需要不同的构造。
  • 实例化客户端。这包括创建客户端实例并将其连接到选定的传输方法。
  • 决定要列出的资源。您的 MCP 服务器提供资源、工具和提示,您需要决定列出哪些内容。
  • 将客户端集成到主机应用程序中。一旦了解了服务器的功能,您需要将其集成到主机应用程序中,以便用户输入提示或其他命令时,调用相应的服务器功能。

现在我们已经了解了即将进行的操作的总体概况,接下来让我们看一个示例。

示例客户端

让我们看一个示例客户端:

TypeScript

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

const transport = new StdioClientTransport({
  command: "node",
  args: ["server.js"]
});

const client = new Client(
  {
    name: "example-client",
    version: "1.0.0"
  }
);

await client.connect(transport);

// List prompts
const prompts = await client.listPrompts();

// Get a prompt
const prompt = await client.getPrompt({
  name: "example-prompt",
  arguments: {
    arg1: "value"
  }
});

// List resources
const resources = await client.listResources();

// Read a resource
const resource = await client.readResource({
  uri: "file:///example.txt"
});

// Call a tool
const result = await client.callTool({
  name: "example-tool",
  arguments: {
    arg1: "value"
  }
});

在上述代码中,我们:

  • 导入了库。
  • 创建了一个客户端实例,并使用 stdio 作为传输方式进行连接。
  • 列出了提示、资源和工具,并调用了它们。

就是这样,一个可以与 MCP 服务器通信的客户端。

接下来,我们将在练习部分逐步分解每段代码并解释其作用。

练习:编写客户端

如上所述,我们将逐步解释代码,当然,如果您愿意,可以跟着一起编写代码。

-1- 导入库

让我们导入所需的库,我们需要引用客户端和选定的传输协议 stdio。stdio 是一种用于本地运行的协议。SSE 是另一种传输协议,我们将在后续章节中展示,但这是您的另一个选择。现在,让我们继续使用 stdio。

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;

接下来是实例化。

-2- 实例化客户端和传输

我们需要创建传输实例以及客户端实例:

.NET

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol;

var builder = Host.CreateApplicationBuilder(args);

builder.Configuration.AddEnvironmentVariables().AddUserSecrets<Program>();

var clientTransport = new StdioClientTransport(new()
{
    Name = "Demo Server",
    Command = "dotnet",
    Arguments = ["run", "--project", @"F:\dht\SLM\Source\McpCalculatorServer\McpCalculatorServer.csproj"],
});

await using var mcpClient = await McpClientFactory.CreateAsync(clientTransport);

在上述代码中,我们:

  • 导入了所需的库。
  • 创建了一个 stdio 传输,并创建了一个客户端 mcpClient。后者是我们用来列出和调用 MCP 服务器功能的工具。

注意,在 "Arguments" 中,您可以指向 .csproj 或可执行文件。

-3- 列出服务器功能

现在,我们有一个可以连接的客户端,但程序运行时它实际上并没有列出其功能,因此接下来让我们完成这一部分:

.NET

foreach(var tool in await mcpClient.ListToolsAsync())
{
    Console.WriteLine($"{tool.Name} ({tool.Description})");
}

以上是一个列出服务器工具的示例。对于每个工具,我们打印出其名称。

-4- 调用功能

要调用功能,我们需要确保指定正确的参数,有时还需要指定我们尝试调用的名称。

.NET

  1. 添加一些代码以调用工具:
    var result = await mcpClient.CallToolAsync("add", new Dictionary<string, object?>() { ["a"] = 1, ["b"] = 3 }, cancellationToken: CancellationToken.None);
  2. 打印结果,以下是处理结果的代码:
    var res = result.Content.First(c => c.Type == "text");
    if (res is TextContentBlock textContentBlock)
    {
        Console.WriteLine(textContentBlock.Text);
    }

-5- 运行客户端

要运行客户端,请在终端中输入以下命令:

.NET

dotnet run

作业

在本次作业中,您将使用所学内容创建自己的客户端。

以下是您可以使用的服务器,您需要通过客户端代码调用它,看看是否可以为服务器添加更多功能,使其更有趣。

.NET

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using ModelContextProtocol.Server;
using System.ComponentModel;

var builder = Host.CreateApplicationBuilder(args);
builder.Logging.AddConsole(consoleLogOptions =>
{
    // Configure all logs to go to stderr
    consoleLogOptions.LogToStandardErrorThreshold = LogLevel.Trace;
});

builder.Services
    .AddMcpServer()
    .WithStdioServerTransport()
    .WithToolsFromAssembly();
await builder.Build().RunAsync();

[McpServerToolType]
public static class CalculatorTool
{
    [McpServerTool, Description("Adds two numbers")]
    public static string Add(int a, int b) => $"Sum {a + b}";
}

查看此项目以了解如何 添加提示和资源

同时,查看此链接以了解如何调用 提示和资源

解决方案

解决方案文件夹包含完整的、可运行的客户端实现,展示了本教程中涵盖的所有概念。每个解决方案包括客户端和服务器代码,组织为独立的项目。

📁 解决方案结构

解决方案目录按编程语言组织:

solution/
├── typescript/          # TypeScript client with npm/Node.js setup
│   ├── package.json     # Dependencies and scripts
│   ├── tsconfig.json    # TypeScript configuration
│   └── src/             # Source code
├── java/                # Java Spring Boot client project
│   ├── pom.xml          # Maven configuration
│   ├── src/             # Java source files
│   └── mvnw             # Maven wrapper
├── python/              # Python client implementation
│   ├── client.py        # Main client code
│   ├── server.py        # Compatible server
│   └── README.md        # Python-specific instructions
├── dotnet/              # .NET client project
│   ├── dotnet.csproj    # Project configuration
│   ├── Program.cs       # Main client code
│   └── dotnet.sln       # Solution file
├── rust/                # Rust client implementation
|  ├── Cargo.lock        # Cargo lock file
|  ├── Cargo.toml        # Project configuration and dependencies
|  ├── src               # Source code
|  │   └── main.rs       # Main client code
└── server/              # Additional .NET server implementation
    ├── Program.cs       # Server code
    └── server.csproj    # Server project file

🚀 每个解决方案包含的内容

每个语言特定的解决方案提供:

  • 完整的客户端实现,包含本教程中的所有功能。
  • 工作项目结构,具有适当的依赖项和配置。
  • 构建和运行脚本,便于设置和执行。
  • 详细的 README,提供语言特定的说明。
  • 错误处理和结果处理示例。

📖 使用解决方案

  1. 导航到您选择的语言文件夹

    cd solution/typescript/    # For TypeScript
    cd solution/java/          # For Java
    cd solution/python/        # For Python
    cd solution/dotnet/        # For .NET
  2. 按照每个文件夹中的 README 说明

    • 安装依赖项
    • 构建项目
    • 运行客户端
  3. 您应该看到的示例输出

    Prompt: Please review this code: console.log("hello");
    Resource template: file
    Tool result: { content: [ { type: 'text', text: '9' } ] }

     

有关完整文档和逐步说明,请参阅:📖 解决方案文档

🎯 完整示例

我们提供了所有编程语言的完整、可运行的客户端实现。这些示例展示了上述功能的全部内容,可用作参考实现或您自己项目的起点。

可用的完整示例

语言 文件 描述
Java client_example_java.java 使用 SSE 传输的完整 Java 客户端,包含全面的错误处理
C# client_example_csharp.cs 使用 stdio 传输的完整 C# 客户端,支持自动服务器启动
TypeScript client_example_typescript.ts 完整的 TypeScript 客户端,支持所有 MCP 协议功能
Python client_example_python.py 使用 async/await 模式的完整 Python 客户端
Rust client_example_rust.rs 使用 Tokio 进行异步操作的完整 Rust 客户端
每个完整示例包括:    
  • ✅ 连接建立和错误处理
  • ✅ 服务器发现(工具、资源、提示等,视情况而定)
  • ✅ 计算器操作(加、减、乘、除、帮助)
  • ✅ 结果处理和格式化输出
  • ✅ 全面的错误处理
  • ✅ 清晰、带注释的代码,包含逐步说明

开始使用完整示例

  1. 从上表中选择您偏好的语言
  2. 查看完整示例文件,以了解完整实现
  3. 按照complete_examples.md中的说明运行示例
  4. 根据您的具体用例修改和扩展示例

有关运行和自定义这些示例的详细文档,请参阅:📖 完整示例文档

💡 解决方案与完整示例的对比

解决方案文件夹 完整示例
包含构建文件的完整项目结构 单文件实现
带依赖项的即用型项目 专注于代码示例
类生产环境的设置 教学参考
语言特定的工具链 跨语言对比

这两种方法各有价值——对于完整项目,请使用解决方案文件夹;对于学习和参考,请使用完整示例

关键要点

本章的关键要点如下,关于客户端的内容:

  • 客户端既可以用于发现服务器功能,也可以调用服务器功能。
  • 客户端可以在自身启动时启动服务器(如本章所述),但也可以连接到已运行的服务器。
  • 客户端是测试服务器功能的绝佳方式,与上一章提到的Inspector等替代方案相比,具有独特优势。 
posted @ 2025-09-14 21:06  菜鸟吊思  阅读(5)  评论(0)    收藏  举报