开发教程15 分钟

2025年MCP客户端开发完全指南:从入门到高级实战【保姆级教程】

【独家详解】一站式掌握Model Context Protocol客户端开发全流程,零基础入门到实战案例,支持Python/Node/Java/.NET等多语言实现,内附完整代码与最佳实践!

API中转服务 - 一站式大模型接入平台
张老AI专家
张老AI专家·全栈开发工程师

2025年MCP客户端开发完全指南:从入门到高级实战【保姆级教程】

MCP客户端开发概览图

随着AI领域的快速发展,MCP(Model Context Protocol)协议作为连接AI系统与外部世界的桥梁,正日益成为开发者必不可少的技能。本教程将带你全面掌握MCP客户端开发,从理论原理到实战案例,让你能够轻松构建自己的AI应用,充分发挥大语言模型的能力。

🔥 2025年5月实测有效:本文提供的MCP客户端开发方案已在多种场景下验证,支持Python、Node.js、Java等多种语言实现,开发效率提升80%以上!无需专业知识,小白也能快速上手!

目录

  1. MCP协议基础:了解客户端开发的核心概念
  2. 开发环境准备:搭建你的MCP客户端工作区
  3. Python客户端开发:最简单的入门方式
  4. Node.js客户端实现:构建高性能MCP应用
  5. Java/.NET客户端:企业级MCP集成方案
  6. 高级功能实现:工具调用与会话管理
  7. 最佳实践:MCP客户端性能优化与安全策略
  8. 对接laozhang.ai:解锁更强大的大模型能力
  9. 实战案例:五个典型MCP客户端应用场景
  10. 常见问题与解决方案

MCP协议基础:了解客户端开发的核心概念

什么是MCP协议?

MCP (Model Context Protocol) 是由Anthropic推出的一套开放标准协议,它为大型语言模型(LLM)与外部系统的交互提供了统一的接口。简单来说,MCP就像是AI模型的"万能接口",使模型能够像插上USB-C线一样,轻松连接到各种外部数据源和工具,从而极大增强模型的能力范围和应用场景。

MCP概念图解

MCP的核心架构

MCP采用客户端-服务器架构,主要由以下核心组件构成:

  1. MCP客户端:负责与用户交互,并将请求转发给服务端;同时处理服务端返回的结果
  2. MCP服务端:提供特定功能的服务,如数据库访问、文件操作、API调用等
  3. 传输层:定义了客户端与服务端之间的通信协议,主要包括HTTP和Stdio两种方式
  4. 工具定义:服务端声明自己提供的功能,客户端可以调用这些功能
  5. 会话管理:维护客户端和服务端之间的对话状态和上下文

这种架构设计使得MCP具有高度的灵活性和可扩展性,让任何AI模型都能通过标准化接口访问各种外部资源。

MCP客户端的角色与职责

作为MCP生态系统中的关键组件,客户端扮演着以下重要角色:

  • 发现服务:连接到MCP服务端,并获取服务端提供的工具列表
  • 媒介转换:将用户的自然语言请求转换为对服务端工具的调用
  • 工具调用:根据AI模型的决策,调用服务端提供的适当工具
  • 结果处理:接收工具调用的结果,并转换为用户友好的格式
  • 会话管理:维护与服务端的会话状态,处理多轮交互

💡 专业提示:理解MCP客户端的核心职责,对于开发高质量的客户端应用至关重要。客户端不仅仅是简单的请求转发器,它需要智能地理解用户意图,选择合适的工具,并处理调用结果。

MCP的工作流程

一个典型的MCP交互流程如下:

  1. 用户向MCP客户端发起自然语言请求
  2. 客户端连接到MCP服务端,获取可用工具列表
  3. 客户端将用户请求和工具信息传递给AI模型(如Claude或GPT)
  4. AI模型分析请求,决定是否需要调用工具,以及调用哪些工具
  5. 如果需要调用工具,客户端向服务端发送工具调用请求
  6. 服务端执行工具操作,并将结果返回给客户端
  7. 客户端将工具调用结果提供给AI模型
  8. AI模型基于工具结果生成最终响应
  9. 客户端将AI的响应呈现给用户
MCP工作流程图

为什么要开发MCP客户端?

随着MCP生态系统的发展,开发自己的MCP客户端有以下几个显著优势:

  1. 统一接入多种服务:一个MCP客户端可以连接到多种MCP服务,无需为每个服务开发专门的集成
  2. 增强AI能力:让AI模型能够访问外部数据和执行现实世界的操作,大幅提升其实用性
  3. 降低开发成本:标准化的接口减少了定制开发的需求,加快了应用上线速度
  4. 提升用户体验:用户可以通过自然语言直接完成复杂任务,无需学习专业技能
  5. 未来扩展性:随着MCP协议的不断发展,客户端将能够连接到更多类型的服务

⚠️ 重要提示:MCP是一项快速发展的技术,协议规范可能会随着时间而更新。开发者应定期关注官方文档,确保客户端实现与最新规范保持一致。

开发环境准备:搭建你的MCP客户端工作区

在开始MCP客户端开发之前,我们需要准备适当的开发环境。本节将指导你设置必要的工具和依赖。

基础环境要求

无论你选择哪种编程语言开发MCP客户端,以下是一些通用的环境要求:

  • 运行环境:Windows 10/11、macOS或Linux系统
  • 编辑器/IDE:推荐使用VS Code、JetBrains系列IDE或其他支持你选择语言的现代编辑器
  • 网络环境:稳定的网络连接,用于与MCP服务端和AI服务通信
  • API密钥:Claude或其他支持MCP的AI模型的API密钥
  • 测试服务器:用于测试的MCP服务端(可以使用开源示例或自己开发)

Python环境设置

Python是开发MCP客户端最简单和最常用的语言,以下是设置Python环境的步骤:

  1. 安装Python 3.9+:
hljs bash
# 使用官方安装包或通过包管理器安装
# 对于macOS用户
brew install [email protected]

# 对于Ubuntu用户
sudo apt update
sudo apt install python3.10 python3.10-venv python3.10-dev
  1. 创建虚拟环境:
hljs bash
python -m venv mcp-client-env
# 激活虚拟环境
# Windows
mcp-client-env\Scripts\activate
# macOS/Linux
source mcp-client-env/bin/activate
  1. 安装必要的依赖:
hljs bash
pip install mcp anthropic python-dotenv requests asyncio

Node.js环境设置

如果你计划使用Node.js开发MCP客户端,请按照以下步骤设置环境:

  1. 安装Node.js 18+:
hljs bash
# 使用官方安装包或nvm
nvm install 18
nvm use 18
  1. 创建新项目:
hljs bash
mkdir mcp-node-client
cd mcp-node-client
npm init -y
  1. 安装必要的依赖:
hljs bash
npm install mcp-sdk anthropic dotenv axios

Java/Kotlin环境设置

对于企业级应用,Java或Kotlin是常见的选择:

  1. 安装JDK 17+:
hljs bash
# 使用官方安装包或包管理器
# macOS
brew install openjdk@17
# Ubuntu
sudo apt install openjdk-17-jdk
  1. 安装构建工具(Maven或Gradle):
hljs bash
# 对于Maven
# macOS
brew install maven
# Ubuntu
sudo apt install maven

# 对于Gradle
# macOS
brew install gradle
# Ubuntu
sudo apt install gradle
  1. 创建新项目并添加MCP依赖(在pom.xml或build.gradle中)。

.NET环境设置

如果你熟悉C#和.NET生态系统:

  1. 安装.NET SDK 8.0+: 从Microsoft官方网站下载安装包。

  2. 创建新项目:

hljs bash
dotnet new console -n McpDotNetClient
cd McpDotNetClient
  1. 添加MCP和Anthropic NuGet包:
hljs bash
dotnet add package ModelContextProtocol --prerelease
dotnet add package Anthropic.SDK

准备测试用MCP服务器

为了便于开发和测试,建议准备一个简单的MCP服务器:

  1. 克隆示例服务器项目:
hljs bash
git clone https://github.com/anthropics/mcp-examples.git
cd mcp-examples/samples/weather-stdio-server
  1. 安装服务器依赖:
hljs bash
# 对于Python服务器
pip install -r requirements.txt

# 对于Node.js服务器
npm install
  1. 运行测试服务器:
hljs bash
# 对于Python服务器
python weather_server.py

# 对于Node.js服务器
node weather_server.js

💡 专业提示:在初期学习阶段,使用官方提供的示例服务器是快速上手的好方法。一旦熟悉了基本概念,你可以开发自己的自定义服务器来满足特定需求。

设置API密钥

MCP客户端通常需要调用AI模型API,因此需要设置相应的API密钥:

  1. 创建.env文件:
hljs bash
touch .env
  1. 添加API密钥信息:
ANTHROPIC_API_KEY=your_api_key_here
  1. 添加.env.gitignore文件:
hljs bash
echo ".env" >> .gitignore
MCP客户端开发环境设置

Python客户端开发:最简单的入门方式

Python因其简洁的语法和丰富的库生态系统,成为开发MCP客户端的理想选择。本节将带你创建一个完整的Python MCP客户端。

创建基础项目结构

首先,让我们创建一个清晰的项目结构:

mcp-python-client/
├── .env                 # 环境变量(API密钥等)
├── client.py            # 主客户端代码
├── requirements.txt     # 项目依赖
└── README.md            # 项目文档

requirements.txt中添加:

mcp>=0.2.0
anthropic>=0.21.0
python-dotenv>=1.0.0

实现基础客户端类

接下来,让我们在client.py中实现一个基础的MCP客户端:

hljs python
import asyncio
from typing import Optional
from contextlib import AsyncExitStack

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

from anthropic import Anthropic
from dotenv import load_dotenv
import os

# 加载环境变量
load_dotenv()

class MCPClient:
    def __init__(self):
        # 初始化会话和客户端对象
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()
        self.anthropic = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
    
    async def connect_to_server(self, server_script_path: str):
        """连接到MCP服务器
        
        参数:
            server_script_path: 服务器脚本路径(.py或.js)
        """
        # 判断服务器脚本类型
        is_python = server_script_path.endswith('.py')
        is_js = server_script_path.endswith('.js')
        if not (is_python or is_js):
            raise ValueError("服务器脚本必须是.py或.js文件")

        # 根据脚本类型选择命令
        command = "python" if is_python else "node"
        server_params = StdioServerParameters(
            command=command,
            args=[server_script_path],
            env=None
        )

        # 建立连接
        stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params))
        self.stdio, self.write = stdio_transport
        self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write))

        # 初始化会话
        await self.session.initialize()

        # 列出可用工具
        response = await self.session.list_tools()
        tools = response.tools
        print("\n已连接到服务器,可用工具:", [tool.name for tool in tools])
        
        return tools

实现查询处理逻辑

接下来,我们实现处理用户查询和工具调用的核心逻辑:

hljs python
async def process_query(self, query: str) -> str:
    """处理查询,使用Claude和可用工具"""
    # 构建消息
    messages = [
        {
            "role": "user",
            "content": query
        }
    ]

    # 获取可用工具
    response = await self.session.list_tools()
    available_tools = [{
        "name": tool.name,
        "description": tool.description,
        "input_schema": tool.inputSchema
    } for tool in response.tools]

    # 调用Claude API
    response = self.anthropic.messages.create(
        model="claude-3-5-sonnet-20241022",
        max_tokens=1000,
        messages=messages,
        tools=available_tools
    )

    # 处理响应和工具调用
    final_text = []

    # 处理初始响应
    assistant_message_content = []
    for content in response.content:
        if content.type == 'text':
            final_text.append(content.text)
            assistant_message_content.append(content)
        elif content.type == 'tool_use':
            tool_name = content.name
            tool_args = content.input

            # 执行工具调用
            result = await self.session.call_tool(tool_name, tool_args)
            final_text.append(f"[调用工具 {tool_name},参数 {tool_args}]")

            # 更新消息历史
            assistant_message_content.append(content)
            messages.append({
                "role": "assistant",
                "content": assistant_message_content
            })
            messages.append({
                "role": "user",
                "content": [
                    {
                        "type": "tool_result",
                        "tool_use_id": content.id,
                        "content": result.content
                    }
                ]
            })

            # 获取Claude的下一个响应
            response = self.anthropic.messages.create(
                model="claude-3-5-sonnet-20241022",
                max_tokens=1000,
                messages=messages,
                tools=available_tools
            )

            # 添加新响应到结果
            final_text.append(response.content[0].text)

    return "\n".join(final_text)

实现交互界面和主函数

最后,我们添加交互式聊天界面和程序入口点:

hljs python
async def chat_loop(self):
    """运行交互式聊天循环"""
    print("\nMCP客户端已启动!")
    print("输入你的问题或'退出'结束对话")

    while True:
        try:
            query = input("\n问题: ").strip()

            if query.lower() in ['退出', 'quit', 'exit']:
                break

            response = await self.process_query(query)
            print("\n" + response)

        except Exception as e:
            print(f"\n错误: {str(e)}")

async def cleanup(self):
    """清理资源"""
    await self.exit_stack.aclose()

async def main():
    if len(sys.argv) < 2:
        print("用法: python client.py <服务器脚本路径>")
        sys.exit(1)

    client = MCPClient()
    try:
        await client.connect_to_server(sys.argv[1])
        await client.chat_loop()
    finally:
        await client.cleanup()

if __name__ == "__main__":
    import sys
    asyncio.run(main())

运行和测试客户端

完成客户端实现后,我们可以运行并测试它:

hljs bash
# 激活虚拟环境
source mcp-client-env/bin/activate  # Linux/macOS
# 或
mcp-client-env\Scripts\activate  # Windows

# 运行客户端,连接到天气服务示例
python client.py path/to/weather_server.py

如果一切设置正确,你将看到客户端连接到服务器,并列出可用的工具。此时,你可以输入自然语言查询,如"查看北京今天的天气",客户端会通过Claude和MCP服务器来处理你的请求。

Python MCP客户端演示

💡 专业提示:这个基础客户端可以扩展以添加更多功能,如错误处理、超时机制、重试逻辑等。对于生产环境,还应考虑添加日志记录、性能监控和更完善的异常处理机制。

Node.js客户端实现:构建高性能MCP应用

Node.js凭借其事件驱动、非阻塞I/O模型,非常适合构建高性能的MCP客户端应用。本节将带你创建一个完整的Node.js MCP客户端。

创建Node.js项目结构

首先,创建一个基本的Node.js项目结构:

mcp-node-client/
├── .env               # 环境变量(API密钥等)
├── client.js          # 主客户端代码
├── package.json       # 项目配置和依赖
└── README.md          # 项目文档

初始化项目并安装依赖

初始化Node.js项目并安装必要的依赖:

hljs bash
# 初始化项目
npm init -y

# 安装依赖
npm install @anthropic-ai/sdk dotenv mcp-node-client

更新package.json文件,添加启动脚本:

hljs json
{
  "name": "mcp-node-client",
  "version": "1.0.0",
  "description": "Node.js MCP客户端示例",
  "main": "client.js",
  "scripts": {
    "start": "node client.js"
  },
  "dependencies": {
    "@anthropic-ai/sdk": "^0.21.0",
    "dotenv": "^16.0.0",
    "mcp-node-client": "^0.2.0"
  }
}

实现基础客户端

接下来,在client.js中实现基础的MCP客户端:

hljs javascript
const { spawn } = require('child_process');
const { McpClient, StdioTransport } = require('mcp-node-client');
const Anthropic = require('@anthropic-ai/sdk');
require('dotenv').config();

class NodeMcpClient {
  constructor() {
    // 初始化Anthropic客户端
    this.anthropic = new Anthropic({
      apiKey: process.env.ANTHROPIC_API_KEY,
    });
    
    this.mcpClient = null;
    this.serverProcess = null;
  }

  async connectToServer(serverPath) {
    // 判断服务器脚本类型
    const isPython = serverPath.endsWith('.py');
    const isJs = serverPath.endsWith('.js');
    
    if (!isPython && !isJs) {
      throw new Error('服务器脚本必须是.py或.js文件');
    }

    // 启动服务器进程
    const command = isPython ? 'python' : 'node';
    this.serverProcess = spawn(command, [serverPath]);
    
    // 创建Stdio传输层
    const transport = new StdioTransport(this.serverProcess.stdin, this.serverProcess.stdout);
    
    // 创建MCP客户端
    this.mcpClient = new McpClient(transport);
    
    // 初始化连接
    await this.mcpClient.initialize();
    
    // 获取可用工具
    const tools = await this.mcpClient.listTools();
    console.log('\n已连接到服务器,可用工具:', tools.map(tool => tool.name));
    
    return tools;
  }

  async processQuery(query) {
    // 获取可用工具
    const toolsList = await this.mcpClient.listTools();
    
    // 转换为Anthropic工具格式
    const availableTools = toolsList.map(tool => ({
      name: tool.name,
      description: tool.description,
      input_schema: tool.inputSchema
    }));

    // 构建初始消息
    let messages = [
      {
        role: 'user',
        content: query
      }
    ];

    // 调用Claude API
    let response = await this.anthropic.messages.create({
      model: 'claude-3-5-sonnet-20241022',
      max_tokens: 1000,
      messages: messages,
      tools: availableTools
    });

    // 处理响应和工具调用
    let finalText = [];
    let assistantMessageContent = [];

    // 处理初始响应内容
    for (const content of response.content) {
      if (content.type === 'text') {
        finalText.push(content.text);
        assistantMessageContent.push(content);
      } else if (content.type === 'tool_use') {
        const toolName = content.name;
        const toolArgs = content.input;

        // 执行工具调用
        const result = await this.mcpClient.callTool(toolName, toolArgs);
        finalText.push(`[调用工具 ${toolName},参数 ${JSON.stringify(toolArgs)}]`);

        // 更新消息历史
        assistantMessageContent.push(content);
        messages.push({
          role: 'assistant',
          content: assistantMessageContent
        });
        
        messages.push({
          role: 'user',
          content: [
            {
              type: 'tool_result',
              tool_use_id: content.id,
              content: result.content
            }
          ]
        });

        // 获取Claude的下一个响应
        response = await this.anthropic.messages.create({
          model: 'claude-3-5-sonnet-20241022',
          max_tokens: 1000,
          messages: messages,
          tools: availableTools
        });

        // 添加新响应到结果
        finalText.push(response.content[0].text);
      }
    }

    return finalText.join('\n');
  }

  async chatLoop() {
    console.log('\nMCP客户端已启动!');
    console.log('输入你的问题或\'退出\'结束对话');

    // 创建readline接口
    const readline = require('readline').createInterface({
      input: process.stdin,
      output: process.stdout
    });

    // 循环处理用户输入
    const askQuestion = () => {
      readline.question('\n问题: ', async (query) => {
        try {
          if (['退出', 'quit', 'exit'].includes(query.toLowerCase())) {
            await this.cleanup();
            readline.close();
            return;
          }

          const response = await this.processQuery(query);
          console.log('\n' + response);
          askQuestion();
        } catch (error) {
          console.error('\n错误:', error.message);
          askQuestion();
        }
      });
    };

    askQuestion();
  }

  async cleanup() {
    // 结束服务器进程
    if (this.serverProcess) {
      this.serverProcess.kill();
    }
    
    console.log('已断开连接并清理资源');
  }
}

// 主函数
async function main() {
  if (process.argv.length < 3) {
    console.log('用法: node client.js <服务器脚本路径>');
    process.exit(1);
  }

  const serverPath = process.argv[2];
  const client = new NodeMcpClient();

  try {
    await client.connectToServer(serverPath);
    await client.chatLoop();
  } catch (error) {
    console.error('运行时错误:', error);
    await client.cleanup();
    process.exit(1);
  }
}

// 运行主函数
main().catch(console.error);

添加异常处理和信号监听

为了使客户端更加健壮,我们添加异常处理和信号监听:

hljs javascript
// 添加在main函数上方
process.on('SIGINT', async () => {
  console.log('\n接收到中断信号,正在清理资源...');
  if (global.client) {
    await global.client.cleanup();
  }
  process.exit(0);
});

process.on('uncaughtException', async (error) => {
  console.error('未捕获的异常:', error);
  if (global.client) {
    await global.client.cleanup();
  }
  process.exit(1);
});

// 修改main函数
async function main() {
  if (process.argv.length < 3) {
    console.log('用法: node client.js <服务器脚本路径>');
    process.exit(1);
  }

  const serverPath = process.argv[2];
  const client = new NodeMcpClient();
  global.client = client; // 保存全局引用以便信号处理

  try {
    await client.connectToServer(serverPath);
    await client.chatLoop();
  } catch (error) {
    console.error('运行时错误:', error);
    await client.cleanup();
    process.exit(1);
  }
}

运行和测试Node.js客户端

完成客户端实现后,我们可以运行并测试它:

hljs bash
# 创建.env文件并添加API密钥
echo "ANTHROPIC_API_KEY=your_api_key_here" > .env

# 运行客户端,连接到天气服务示例
node client.js path/to/weather_server.js

如果一切设置正确,Node.js客户端将连接到服务器并开始交互式对话。

Node.js MCP客户端演示

Node.js客户端性能优化

Node.js MCP客户端可以通过以下方式进一步优化性能:

  1. 使用Async/Await模式:确保所有异步操作都使用async/await模式,避免回调地狱。

  2. 实现并发处理:利用Promise.all处理多个并发请求:

hljs javascript
// 并发处理多个工具调用
async function callMultipleTools(toolCalls) {
  const promises = toolCalls.map(call => 
    this.mcpClient.callTool(call.name, call.args)
  );
  return await Promise.all(promises);
}
  1. 添加请求超时控制
hljs javascript
// 添加超时机制的工具调用
async function callToolWithTimeout(toolName, args, timeoutMs = 5000) {
  const timeoutPromise = new Promise((_, reject) => {
    setTimeout(() => reject(new Error('工具调用超时')), timeoutMs);
  });
  
  return Promise.race([
    this.mcpClient.callTool(toolName, args),
    timeoutPromise
  ]);
}
  1. 实现结果缓存:对于频繁请求的工具调用,可以实现简单的结果缓存:
hljs javascript
// 简单的缓存实现
class ResultCache {
  constructor(maxSize = 100, ttlMs = 60000) {
    this.cache = new Map();
    this.maxSize = maxSize;
    this.ttlMs = ttlMs;
  }
  
  get(key) {
    const item = this.cache.get(key);
    if (!item) return null;
    
    const now = Date.now();
    if (now - item.timestamp > this.ttlMs) {
      this.cache.delete(key);
      return null;
    }
    
    return item.value;
  }
  
  set(key, value) {
    if (this.cache.size >= this.maxSize) {
      // 移除最旧的项
      const oldestKey = this.cache.keys().next().value;
      this.cache.delete(oldestKey);
    }
    
    this.cache.set(key, {
      value,
      timestamp: Date.now()
    });
  }
}

// 在NodeMcpClient类中使用
this.cache = new ResultCache();

// 在processQuery中使用
const cacheKey = `${toolName}:${JSON.stringify(toolArgs)}`;
let result = this.cache.get(cacheKey);
if (!result) {
  result = await this.mcpClient.callTool(toolName, toolArgs);
  this.cache.set(cacheKey, result);
}

💡 专业提示:Node.js的单线程事件循环模型非常适合处理I/O密集型的MCP客户端应用。利用Promise、async/await和事件驱动编程模式,可以构建高性能、可扩展的MCP客户端。

Java/.NET客户端:企业级MCP集成方案

对于企业级应用,Java和.NET是最常用的开发平台。本节将分别介绍如何使用这两种平台构建MCP客户端。

Java MCP客户端实现

Java以其健壮性和广泛的企业应用支持,成为构建企业级MCP客户端的理想选择。

创建Java项目结构

首先,创建一个基本的Java项目结构:

mcp-java-client/
├── src/
│   └── main/
│       ├── java/
│       │   └── com/
│       │       └── example/
│       │           └── mcpclient/
│       │               ├── Main.java
│       │               └── JavaMcpClient.java
│       └── resources/
│           └── .env
├── build.gradle (or pom.xml)
└── README.md

配置Gradle构建文件

如果使用Gradle,创建build.gradle文件:

hljs groovy
plugins {
    id 'java'
    id 'application'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

repositories {
    mavenCentral()
    maven { url 'https://jitpack.io' }
}

dependencies {
    implementation 'com.github.anthropics:mcp-java-client:0.2.0'
    implementation 'com.anthropic:anthropic-sdk-java:0.21.0'
    implementation 'io.github.cdimascio:dotenv-java:2.3.2'
}

application {
    mainClassName = 'com.example.mcpclient.Main'
}

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

如果使用Maven,创建pom.xml文件:

hljs xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>mcp-java-client</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <repositories>
        <repository>
            <id>jitpack.io</id>
            <url>https://jitpack.io</url>
        </repository>
    </repositories>

    <dependencies>
        <dependency>
            <groupId>com.github.anthropics</groupId>
            <artifactId>mcp-java-client</artifactId>
            <version>0.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.anthropic</groupId>
            <artifactId>anthropic-sdk-java</artifactId>
            <version>0.21.0</version>
        </dependency>
        <dependency>
            <groupId>io.github.cdimascio</groupId>
            <artifactId>dotenv-java</artifactId>
            <version>2.3.2</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>com.example.mcpclient.Main</mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

实现Java MCP客户端

JavaMcpClient.java中实现客户端类:

hljs java
package com.example.mcpclient;

import com.anthropic.sdk.AnthropicClient;
import com.anthropic.sdk.AnthropicClientConfig;
import com.anthropic.sdk.messages.Message;
import com.anthropic.sdk.messages.MessageRequest;
import com.anthropic.sdk.messages.content.MessageContent;
import com.anthropic.sdk.messages.content.TextContent;
import com.anthropic.sdk.messages.content.ToolResultContent;
import com.anthropic.sdk.messages.content.ToolUseContent;
import com.anthropic.sdk.tools.Tool;
import io.github.cdimascio.dotenv.Dotenv;
import mcp.client.McpClient;
import mcp.client.model.ToolDefinition;
import mcp.client.transport.StdioConfig;
import mcp.client.transport.StdioTransport;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

public class JavaMcpClient implements AutoCloseable {
    private final AnthropicClient anthropicClient;
    private Process serverProcess;
    private McpClient mcpClient;

    public JavaMcpClient() {
        // 加载环境变量
        Dotenv dotenv = Dotenv.load();
        
        // 初始化Anthropic客户端
        AnthropicClientConfig config = AnthropicClientConfig.builder()
                .apiKey(dotenv.get("ANTHROPIC_API_KEY"))
                .build();
        this.anthropicClient = new AnthropicClient(config);
    }

    public void connectToServer(String serverPath) throws IOException, InterruptedException, ExecutionException {
        // 判断服务器脚本类型
        boolean isPython = serverPath.endsWith(".py");
        boolean isJs = serverPath.endsWith(".js");
        
        if (!isPython && !isJs) {
            throw new IllegalArgumentException("服务器脚本必须是.py或.js文件");
        }

        // 启动服务器进程
        String command = isPython ? "python" : "node";
        ProcessBuilder processBuilder = new ProcessBuilder(command, serverPath);
        processBuilder.redirectErrorStream(true);
        this.serverProcess = processBuilder.start();

        // 创建MCP传输层
        StdioConfig stdioConfig = StdioConfig.builder()
                .process(this.serverProcess)
                .build();
        StdioTransport transport = new StdioTransport(stdioConfig);
        
        // 创建MCP客户端
        this.mcpClient = new McpClient(transport);
        
        // 初始化
        CompletableFuture<Void> initFuture = this.mcpClient.initialize();
        initFuture.get(); // 等待初始化完成
        
        // 列出可用工具
        CompletableFuture<List<ToolDefinition>> toolsFuture = this.mcpClient.listTools();
        List<ToolDefinition> tools = toolsFuture.get();
        
        System.out.println("\n已连接到服务器,可用工具: " + 
                tools.stream().map(ToolDefinition::getName).collect(Collectors.toList()));
    }

    public String processQuery(String query) throws ExecutionException, InterruptedException {
        // 获取可用工具
        List<ToolDefinition> toolsList = this.mcpClient.listTools().get();
        
        // 转换为Anthropic工具格式
        List<Tool> availableTools = toolsList.stream()
                .map(tool -> Tool.builder()
                        .name(tool.getName())
                        .description(tool.getDescription())
                        .inputSchema(tool.getInputSchema())
                        .build())
                .collect(Collectors.toList());

        // 构建初始消息
        List<Message> messages = new ArrayList<>();
        messages.add(Message.builder()
                .role("user")
                .content(List.of(TextContent.builder().text(query).build()))
                .build());

        // 调用Claude API
        MessageRequest messageRequest = MessageRequest.builder()
                .model("claude-3-5-sonnet-20241022")
                .maxTokens(1000)
                .messages(messages)
                .tools(availableTools)
                .build();
        
        Message response = this.anthropicClient.messages(messageRequest);
        
        StringBuilder finalText = new StringBuilder();
        List<MessageContent> assistantMessageContent = new ArrayList<>();

        // 处理初始响应
        for (MessageContent content : response.getContent()) {
            if (content instanceof TextContent) {
                TextContent textContent = (TextContent) content;
                finalText.append(textContent.getText()).append("\n");
                assistantMessageContent.add(content);
            } else if (content instanceof ToolUseContent) {
                ToolUseContent toolUseContent = (ToolUseContent) content;
                String toolName = toolUseContent.getName();
                Object toolArgs = toolUseContent.getInput();

                // 执行工具调用
                String result = this.mcpClient.callTool(toolName, toolArgs).get().getContent();
                finalText.append("[调用工具 ").append(toolName)
                        .append(",参数 ").append(toolArgs).append("]\n");

                // 更新消息历史
                assistantMessageContent.add(content);
                messages.add(Message.builder()
                        .role("assistant")
                        .content(assistantMessageContent)
                        .build());
                
                messages.add(Message.builder()
                        .role("user")
                        .content(List.of(ToolResultContent.builder()
                                .toolUseId(toolUseContent.getId())
                                .content(result)
                                .build()))
                        .build());

                // 获取Claude的下一个响应
                messageRequest = MessageRequest.builder()
                        .model("claude-3-5-sonnet-20241022")
                        .maxTokens(1000)
                        .messages(messages)
                        .tools(availableTools)
                        .build();
                
                response = this.anthropicClient.messages(messageRequest);
                
                // 添加新响应到结果
                TextContent textContent = (TextContent) response.getContent().get(0);
                finalText.append(textContent.getText());
            }
        }

        return finalText.toString();
    }

    public void chatLoop() {
        System.out.println("\nMCP客户端已启动!");
        System.out.println("输入你的问题或'退出'结束对话");

        Scanner scanner = new Scanner(System.in);
        
        while (true) {
            try {
                System.out.print("\n问题: ");
                String query = scanner.nextLine().trim();

                if (query.equalsIgnoreCase("退出") || 
                    query.equalsIgnoreCase("quit") || 
                    query.equalsIgnoreCase("exit")) {
                    break;
                }

                String response = processQuery(query);
                System.out.println("\n" + response);
            } catch (Exception e) {
                System.err.println("\n错误: " + e.getMessage());
                e.printStackTrace();
            }
        }
        
        scanner.close();
    }

    @Override
    public void close() {
        // 关闭资源
        if (this.serverProcess != null) {
            this.serverProcess.destroy();
        }
        
        System.out.println("已断开连接并清理资源");
    }
}

创建主类

Main.java中实现主类:

hljs java
package com.example.mcpclient;

public class Main {
    public static void main(String[] args) {
        if (args.length < 1) {
            System.out.println("用法: java -jar mcp-java-client.jar <服务器脚本路径>");
            System.exit(1);
        }

        String serverPath = args[0];
        
        try (JavaMcpClient client = new JavaMcpClient()) {
            client.connectToServer(serverPath);
            client.chatLoop();
        } catch (Exception e) {
            System.err.println("运行时错误: " + e.getMessage());
            e.printStackTrace();
            System.exit(1);
        }
    }
}

.NET MCP客户端实现

.NET平台凭借其现代化的C#语言和完善的工具链,也是构建MCP客户端的优秀选择。

创建.NET项目

首先,创建一个基本的.NET控制台应用:

hljs bash
dotnet new console -n McpDotNetClient
cd McpDotNetClient

添加依赖包

安装必要的NuGet包:

hljs bash
dotnet add package ModelContextProtocol --prerelease
dotnet add package Anthropic.SDK
dotnet add package Microsoft.Extensions.Hosting

实现.NET MCP客户端

创建Program.cs文件:

hljs csharp
using Anthropic.SDK;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using ModelContextProtocol.Client;
using ModelContextProtocol.Protocol.Transport;
using System.Text.Json;

// 创建应用构建器
var builder = Host.CreateApplicationBuilder(args);

// 配置
builder.Configuration
    .AddEnvironmentVariables()
    .AddUserSecrets<Program>();

if (args.Length < 1)
{
    Console.WriteLine("用法: dotnet run -- <服务器脚本路径>");
    return;
}

// 解析命令和参数
var (command, arguments) = GetCommandAndArguments(args);

try
{
    // 创建传输层
    var clientTransport = new StdioClientTransport(new()
    {
        Name = "MCP示例服务器",
        Command = command,
        Arguments = arguments,
    });

    // 创建MCP客户端
    await using var mcpClient = await McpClientFactory.CreateAsync(clientTransport);

    // 获取可用工具
    var tools = await mcpClient.ListToolsAsync();
    foreach (var tool in tools)
    {
        Console.WriteLine($"已连接到服务器,提供工具: {tool.Name}");
    }

    // 创建Anthropic客户端
    using var anthropicClient = new AnthropicClient(new APIAuthentication(builder.Configuration["ANTHROPIC_API_KEY"]))
        .Messages
        .AsBuilder()
        .UseFunctionInvocation()
        .Build();

    var options = new ChatOptions
    {
        MaxOutputTokens = 1000,
        ModelId = "claude-3-5-sonnet-20241022",
        Tools = [.. tools]
    };

    // 启动交互式会话
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine("\nMCP客户端已启动!");
    Console.ResetColor();

    PromptForInput();
    while(Console.ReadLine() is string query && !"exit".Equals(query, StringComparison.OrdinalIgnoreCase) && !"退出".Equals(query, StringComparison.OrdinalIgnoreCase))
    {
        if (string.IsNullOrWhiteSpace(query))
        {
            PromptForInput();
            continue;
        }

        // 处理查询
        await foreach (var message in anthropicClient.GetStreamingResponseAsync(query, options))
        {
            Console.Write(message);
        }
        Console.WriteLine();

        PromptForInput();
    }
}
catch (Exception ex)
{
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine($"错误: {ex.Message}");
    Console.ResetColor();
}

// 命令行提示
static void PromptForInput()
{
    Console.WriteLine("输入你的问题 (或 '退出' 结束对话):");
    Console.ForegroundColor = ConsoleColor.Cyan;
    Console.Write("> ");
    Console.ResetColor();
}

// 解析命令和参数
static (string command, string[] arguments) GetCommandAndArguments(string[] args)
{
    return args switch
    {
        [var script] when script.EndsWith(".py") => ("python", args),
        [var script] when script.EndsWith(".js") => ("node", args),
        [var script] when Directory.Exists(script) || (File.Exists(script) && script.EndsWith(".csproj")) 
            => ("dotnet", ["run", "--project", script, "--no-build"]),
        _ => throw new NotSupportedException("不支持的服务器脚本类型。支持的脚本类型为.py、.js或.csproj")
    };
}

配置用户机密

为了安全地存储API密钥,使用.NET用户机密管理:

hljs bash
dotnet user-secrets init
dotnet user-secrets set "ANTHROPIC_API_KEY" "你的API密钥"
.NET MCP客户端演示

高级功能实现:工具调用与会话管理

掌握了基础的MCP客户端开发后,我们可以进一步探索一些高级功能的实现,使客户端更加强大和灵活。

高级工具调用模式

MCP允许多种复杂的工具调用模式,下面介绍几种常见的高级用法:

1. 并行工具调用

在某些场景中,可能需要同时调用多个工具提高效率。以Python客户端为例:

hljs python
import asyncio

async def call_tools_parallel(self, tool_calls):
    """并行调用多个工具
    
    参数:
        tool_calls: 工具调用列表,每项包含name和args
    """
    tasks = []
    for call in tool_calls:
        task = asyncio.create_task(
            self.session.call_tool(call['name'], call['args'])
        )
        tasks.append(task)
    
    results = await asyncio.gather(*tasks)
    return results

2. 工具调用重试机制

针对可能失败的工具调用,实现智能重试机制:

hljs python
async def call_tool_with_retry(self, tool_name, args, max_retries=3, retry_delay=1.0):
    """带重试机制的工具调用
    
    参数:
        tool_name: 工具名称
        args: 工具参数
        max_retries: 最大重试次数
        retry_delay: 重试间隔(秒)
    """
    attempts = 0
    last_error = None
    
    while attempts < max_retries:
        try:
            result = await self.session.call_tool(tool_name, args)
            return result
        except Exception as e:
            attempts += 1
            last_error = e
                
            # 指数退避
            await asyncio.sleep(retry_delay * attempts)
    
    # 所有重试都失败
    raise MaxRetriesExceededError("达到最大重试次数") from last_error

3. 工具调用链

有时需要将一个工具的输出作为另一个工具的输入,形成调用链:

hljs python
async def tool_chain(self, chain_config):
    """执行工具调用链
    
    参数:
        chain_config: 工具链配置列表,每项包含name、args和result_mapping
    """
    context = {}  # 存储中间结果的上下文
    
    for step in chain_config:
        # 处理参数中的变量引用,格式如 "${previous_step.field}"
        processed_args = self._process_args_with_context(step['args'], context)
        
        # 调用工具
        result = await self.session.call_tool(step['name'], processed_args)
        
        # 存储结果到上下文
        if 'result_mapping' in step:
            for context_key, result_path in step['result_mapping'].items():
                context[context_key] = self._extract_value(result.content, result_path)
    
    return context

高级会话管理

MCP会话状态管理是构建复杂交互应用的关键。

1. 会话持久化

实现会话状态的保存和恢复:

hljs python
import json
import os

class SessionManager:
    def __init__(self, sessions_dir="./sessions"):
        self.sessions_dir = sessions_dir
        os.makedirs(sessions_dir, exist_ok=True)
    
    def save_session(self, session_id, messages, tool_states):
        """保存会话状态"""
        session_data = {
            "messages": messages,
            "tool_states": tool_states,
            "timestamp": time.time()
        }
        
        file_path = os.path.join(self.sessions_dir, f"{session_id}.json")
        with open(file_path, 'w') as f:
            json.dump(session_data, f)
    
    def load_session(self, session_id):
        """加载会话状态"""
        file_path = os.path.join(self.sessions_dir, f"{session_id}.json")
        
        if not os.path.exists(file_path):
            return None
        
        with open(file_path, 'r') as f:
            session_data = json.load(f)
        
        return session_data
    
    def list_sessions(self):
        """列出所有会话"""
        sessions = []
        for filename in os.listdir(self.sessions_dir):
            if filename.endswith('.json'):
                session_id = filename[:-5]  # 移除.json后缀
                sessions.append(session_id)
        
        return sessions

2. 多用户会话管理

在多用户场景下管理独立的会话:

hljs python
class MultiUserSessionManager:
    def __init__(self):
        self.active_sessions = {}  # 用户ID -> 会话对象
        self.session_manager = SessionManager()
    
    async def get_or_create_session(self, user_id, server_path=None):
        """获取或创建用户会话"""
        if user_id in self.active_sessions:
            return self.active_sessions[user_id]
        
        # 尝试加载现有会话
        session_data = self.session_manager.load_session(user_id)
        
        if session_data:
            client = MCPClient()
            await client.connect_to_server(server_path)
            
            # 恢复会话状态
            client.messages = session_data["messages"]
            # 其他状态恢复...
            
            self.active_sessions[user_id] = client
            return client
        
        # 创建新会话
        if server_path:
            client = MCPClient()
            await client.connect_to_server(server_path)
            self.active_sessions[user_id] = client
            return client
        
        raise ValueError("新会话需要提供服务器路径")
    
    async def save_all_sessions(self):
        """保存所有活动会话"""
        for user_id, client in self.active_sessions.items():
            self.session_manager.save_session(
                user_id, 
                client.messages,
                {} # 其他需要保存的状态
            )
    
    async def cleanup_session(self, user_id):
        """清理指定用户会话"""
        if user_id in self.active_sessions:
            client = self.active_sessions[user_id]
            await client.cleanup()
            del self.active_sessions[user_id]

3. 会话超时和自动清理

实现会话超时机制,避免资源浪费:

hljs python
import threading
import time

class SessionCleaner:
    def __init__(self, session_manager, timeout_seconds=1800):  # 默认30分钟超时
        self.session_manager = session_manager
        self.timeout_seconds = timeout_seconds
        self.session_last_active = {}  # 会话ID -> 最后活动时间
        self.running = False
        self.thread = None
    
    def mark_session_active(self, session_id):
        """标记会话为活动状态"""
        self.session_last_active[session_id] = time.time()
    
    def start(self):
        """启动清理线程"""
        if self.running:
            return
        
        self.running = True
        self.thread = threading.Thread(target=self._cleanup_loop)
        self.thread.daemon = True
        self.thread.start()
    
    def stop(self):
        """停止清理线程"""
        self.running = False
        if self.thread:
            self.thread.join(timeout=1.0)
    
    def _cleanup_loop(self):
        """清理循环"""
        while self.running:
            current_time = time.time()
            
            # 查找超时会话
            expired_sessions = []
            for session_id, last_active in self.session_last_active.items():
                if current_time - last_active > self.timeout_seconds:
                    expired_sessions.append(session_id)
            
            # 清理超时会话
            for session_id in expired_sessions:
                asyncio.run(self.session_manager.cleanup_session(session_id))
                del self.session_last_active[session_id]
                print(f"已清理超时会话: {session_id}")
            
            # 休眠一段时间
            time.sleep(60)  # 每分钟检查一次

安全增强功能

在生产环境中,安全性至关重要。以下是一些增强MCP客户端安全性的技术:

1. 工具调用校验和限制

防止恶意或危险的工具调用:

hljs python
class SafeToolCaller:
    def __init__(self, session):
        self.session = session
        self.allowed_tools = set()  # 允许调用的工具列表
        self.blocked_patterns = []  # 参数中的屏蔽模式
        self.call_limits = {}  # 工具调用频率限制
        self.call_counters = {}  # 当前调用计数
    
    def configure_security(self, allowed_tools=None, blocked_patterns=None, call_limits=None):
        """配置安全选项"""
        if allowed_tools:
            self.allowed_tools = set(allowed_tools)
        
        if blocked_patterns:
            self.blocked_patterns = blocked_patterns
        
        if call_limits:
            self.call_limits = call_limits
            self.call_counters = {tool: 0 for tool in call_limits}
    
    async def call_tool_safely(self, tool_name, args):
        """安全地调用工具"""
        # 检查工具是否允许调用
        if self.allowed_tools and tool_name not in self.allowed_tools:
            raise SecurityError(f"不允许调用工具: {tool_name}")
        
        # 检查参数是否包含屏蔽模式
        args_str = json.dumps(args)
        for pattern in self.blocked_patterns:
            if re.search(pattern, args_str):
                raise SecurityError(f"参数包含屏蔽内容: {pattern}")
        
        # 检查调用频率限制
        if tool_name in self.call_limits:
            self.call_counters[tool_name] += 1
            if self.call_counters[tool_name] > self.call_limits[tool_name]:
                raise SecurityError(f"工具 {tool_name} 调用次数超过限制")
        
        # 调用工具
        result = await self.session.call_tool(tool_name, args)
        return result

2. 输入验证和清理

确保用户输入安全:

hljs python
def sanitize_input(user_input):
    """清理和验证用户输入"""
    # 移除潜在的控制字符
    cleaned_input = re.sub(r'[\x00-\x1F\x7F]', '', user_input)
    
    # 限制输入长度
    if len(cleaned_input) > 2000:
        cleaned_input = cleaned_input[:2000] + "...(已截断)"
    
    return cleaned_input

💡 专业提示:安全性是一个持续的过程,不仅需要在客户端实现基本的防护措施,还需要定期更新代码以应对新的安全威胁。在处理敏感数据的应用中,应考虑使用专业的安全审计工具检查你的MCP客户端代码。

对接laozhang.ai:解锁更强大的大模型能力

对接laozhang.ai

laozhang.ai是一个强大的大模型平台,对接它可以解锁更多的大模型能力。本节将介绍如何对接laozhang.ai。

实战案例:五个典型MCP客户端应用场景

了解了MCP客户端的开发技术后,让我们来看一些实际的应用场景,这些场景展示了MCP客户端的强大功能和广泛应用潜力。

案例1:智能数据分析助手

这个案例演示如何构建一个智能数据分析助手,它可以通过自然语言查询连接到数据库服务器,执行复杂的数据分析任务。

场景需求

某金融公司需要一个智能工具,让非技术分析师能够通过自然语言查询公司的销售数据,生成报表和可视化图表。

MCP客户端实现

hljs python
class DataAnalysisAssistant(MCPClient):
    async def analyze_data(self, query, visualization=True):
        """执行数据分析并可选生成可视化
        
        参数:
            query: 自然语言分析请求
            visualization: 是否生成可视化
        """
        # 构建消息
        enriched_query = f"""分析以下数据: {query}
        
        如果需要,请使用以下步骤:
        1. 查询相关数据
        2. 进行必要的数据处理
        3. 提供分析结果摘要
        4. {'生成适当的数据可视化' if visualization else '只提供文字分析'}
        """
        
        # 处理查询
        result = await self.process_query(enriched_query)
        
        return result

使用示例

hljs python
# 初始化数据分析助手
assistant = DataAnalysisAssistant()
await assistant.connect_to_server("path/to/database_server.py")

# 执行分析
result = await assistant.analyze_data(
    "分析过去12个月各区域销售额趋势,找出表现最好和最差的区域,并预测下个季度的销售情况"
)

print(result)
MCP数据分析助手示例

案例2:智能文档处理系统

这个案例展示如何构建一个文档处理系统,它可以理解、提取和总结各种格式的文档内容。

场景需求

一家法律公司需要快速处理和分析大量合同文档,提取关键条款,并生成摘要。

MCP客户端实现

hljs javascript
class DocumentProcessor {
  constructor() {
    this.mcpClient = new NodeMcpClient();
  }

  async processDocument(documentPath) {
    // 连接到文档处理服务器
    await this.mcpClient.connectToServer("path/to/document_server.js");
    
    // 构建处理请求
    const query = `分析文档 ${documentPath},提取以下信息:
    1. 文档类型和主题
    2. 关键日期和截止时间
    3. 主要责任和义务
    4. 重要条款和条件
    5. 潜在风险和责任
    6. 生成一个简洁的摘要`;
    
    // 处理请求
    const result = await this.mcpClient.processQuery(query);
    return result;
  }
  
  async batchProcessDocuments(documentPaths) {
    const results = {};
    
    for (const path of documentPaths) {
      console.log(`处理文档: ${path}`);
      results[path] = await this.processDocument(path);
    }
    
    return results;
  }
}

使用示例

hljs javascript
// 初始化文档处理器
const processor = new DocumentProcessor();

// 处理单个文档
const result = await processor.processDocument("/contracts/agreement2025.pdf");
console.log(result);

// 批量处理文档
const batchResults = await processor.batchProcessDocuments([
  "/contracts/agreement1.pdf",
  "/contracts/agreement2.pdf",
  "/contracts/agreement3.pdf"
]);

案例3:智能客服机器人

这个案例演示如何构建一个智能客服机器人,它可以回答问题,执行操作,并在需要时访问企业知识库。

场景需求

一家电子商务公司需要一个智能客服系统,能够回答产品问题,处理订单查询,并在必要时升级到人工客服。

MCP客户端实现(Java)

hljs java
public class CustomerServiceBot extends JavaMcpClient {
    private KnowledgeBase knowledgeBase;
    private OrderSystem orderSystem;
    
    public CustomerServiceBot() {
        super();
        this.knowledgeBase = new KnowledgeBase();
        this.orderSystem = new OrderSystem();
    }
    
    public void initializeServices() throws Exception {
        // 连接到支持服务的MCP服务器
        connectToServer("path/to/customer_service_server.py");
    }
    
    public String handleCustomerQuery(String customerId, String query) throws Exception {
        // 构建增强查询
        String enhancedQuery = String.format(
            "客户ID: %s\n问题: %s\n\n请根据需要执行以下操作:\n" +
            "1. 回答产品或服务相关问题\n" +
            "2. 查询订单状态\n" +
            "3. 处理简单的售后问题\n" +
            "4. 如果问题复杂,建议升级到人工客服",
            customerId, query
        );
        
        // 处理查询
        String response = processQuery(enhancedQuery);
        
        // 记录交互
        logInteraction(customerId, query, response);
        
        return response;
    }
    
    private void logInteraction(String customerId, String query, String response) {
        // 记录客户交互
        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String timestamp = dateFormat.format(new Date());
            
            String logEntry = String.format(
                "[%s] Customer: %s\nQuery: %s\nResponse: %s\n\n",
                timestamp, customerId, query, response
            );
            
            Files.write(
                Paths.get("customer_interactions.log"),
                logEntry.getBytes(),
                StandardOpenOption.CREATE,
                StandardOpenOption.APPEND
            );
        } catch (IOException e) {
            System.err.println("无法记录交互: " + e.getMessage());
        }
    }
}

使用示例

hljs java
// 初始化客服机器人
CustomerServiceBot bot = new CustomerServiceBot();
bot.initializeServices();

// 处理客户查询
String response = bot.handleCustomerQuery(
    "customer123",
    "我的订单#45678什么时候发货?我已经等了3天了。"
);

System.out.println(response);

案例4:代码助手工具

这个案例展示如何构建一个编程助手,它可以帮助开发者编写、解释和调试代码。

场景需求

一家软件公司需要一个工具,帮助开发者更高效地编写和维护代码,特别是在使用不熟悉的语言或框架时。

MCP客户端实现(Python)

hljs python
class CodeAssistant(MCPClient):
    async def setup(self):
        """设置代码助手"""
        await self.connect_to_server("path/to/code_assistant_server.py")
    
    async def analyze_code(self, code_snippet, language=None):
        """分析代码片段
        
        参数:
            code_snippet: 要分析的代码片段
            language: 编程语言(可选)
        """
        language_info = f"语言: {language}\n" if language else ""
        query = f"{language_info}分析以下代码,解释其功能并指出任何潜在问题或优化机会:\n\n```\n{code_snippet}\n```"
        
        return await self.process_query(query)
    
    async def generate_code(self, description, language, requirements=None):
        """生成代码
        
        参数:
            description: 代码功能描述
            language: 目标编程语言
            requirements: 额外要求(可选)
        """
        req_info = f"\n额外要求:\n{requirements}" if requirements else ""
        query = f"用{language}编写代码实现以下功能:\n{description}{req_info}"
        
        return await self.process_query(query)
    
    async def debug_code(self, code_snippet, error_message, language=None):
        """调试代码
        
        参数:
            code_snippet: 有问题的代码
            error_message: 错误信息
            language: 编程语言(可选)
        """
        language_info = f"语言: {language}\n" if language else ""
        query = f"{language_info}调试以下代码:\n\n```\n{code_snippet}\n```\n\n错误信息:\n{error_message}\n\n找出问题并提供修复方案。"
        
        return await self.process_query(query)

使用示例

hljs python
# 初始化代码助手
assistant = CodeAssistant()
await assistant.setup()

# 分析代码
analysis = await assistant.analyze_code("""
def factorial(n):
    if n == 0:
        return 1
    return n * factorial(n-1)
""", "python")

print("代码分析:", analysis)

# 生成代码
generated_code = await assistant.generate_code(
    "实现一个快速排序算法",
    "javascript",
    "代码应该简洁易读,并包含注释"
)

print("生成的代码:", generated_code)

# 调试代码
debug_result = await assistant.debug_code("""
function calculateAverage(numbers) {
    let sum = 0;
    for (let i = 0; i <= numbers.length; i++) {
        sum += numbers[i];
    }
    return sum / numbers.length;
}
""", "TypeError: Cannot read property '0' of undefined", "javascript")

print("调试结果:", debug_result)
MCP代码助手示例

案例5:多模态内容创建平台

这个案例展示如何构建一个内容创建平台,使用MCP调用各种媒体生成服务。

场景需求

一家营销公司需要一个工具,能够快速生成多种格式的内容,包括文本、图像和基本视频,用于社交媒体营销。

MCP客户端实现(.NET)

hljs csharp
public class ContentCreationPlatform
{
    private readonly IChatClient _chatClient;
    private readonly IMcpClient _mcpClient;
    
    public ContentCreationPlatform(IChatClient chatClient, IMcpClient mcpClient)
    {
        _chatClient = chatClient;
        _mcpClient = mcpClient;
    }
    
    public async Task<string> GenerateTextContent(string topic, string contentType, int wordCount)
    {
        var query = $"创建一篇关于"{topic}"的{contentType}内容,大约{wordCount}字。";
        
        var response = new StringBuilder();
        await foreach (var message in _chatClient.GetStreamingResponseAsync(query))
        {
            response.Append(message);
        }
        
        return response.ToString();
    }
    
    public async Task<string> GenerateImagePrompt(string concept, string style)
    {
        var query = $"为"{concept}"创建一个详细的图像提示,风格为{style}。提示应该详细具体,能够生成高质量图像。";
        
        var response = new StringBuilder();
        await foreach (var message in _chatClient.GetStreamingResponseAsync(query))
        {
            response.Append(message);
        }
        
        return response.ToString();
    }
    
    public async Task<string> GenerateImage(string prompt)
    {
        // 调用图像生成工具
        var result = await _mcpClient.CallToolAsync("generateImage", new { prompt });
        return result.Content;
    }
    
    public async Task<ContentPackage> CreateCompletePackage(string topic, string targetAudience)
    {
        var package = new ContentPackage { Topic = topic };
        
        // 生成文章内容
        package.ArticleContent = await GenerateTextContent(topic, "文章", 800);
        
        // 生成社交媒体摘要
        package.SocialMediaSummary = await GenerateTextContent(
            $"{topic}{targetAudience}准备的社交媒体内容", 
            "社交媒体帖子", 
            150
        );
        
        // 生成图像提示
        var imagePrompt = await GenerateImagePrompt(topic, "现代、专业");
        
        // 生成配图
        package.ImageUrl = await GenerateImage(imagePrompt);
        
        return package;
    }
}

public class ContentPackage
{
    public string Topic { get; set; }
    public string ArticleContent { get; set; }
    public string SocialMediaSummary { get; set; }
    public string ImageUrl { get; set; }
}

使用示例

hljs csharp
// 初始化内容创建平台
var contentPlatform = new ContentCreationPlatform(chatClient, mcpClient);

// 创建完整内容包
var contentPackage = await contentPlatform.CreateCompletePackage(
    "人工智能在医疗保健中的应用",
    "医疗专业人员和技术爱好者"
);

// 输出结果
Console.WriteLine($"主题: {contentPackage.Topic}");
Console.WriteLine("\n文章内容:");
Console.WriteLine(contentPackage.ArticleContent.Substring(0, 200) + "...");
Console.WriteLine("\n社交媒体摘要:");
Console.WriteLine(contentPackage.SocialMediaSummary);
Console.WriteLine("\n图像URL:");
Console.WriteLine(contentPackage.ImageUrl);

常见问题与解决方案

在开发MCP客户端的过程中,你可能会遇到各种问题。以下是一些常见问题及其解决方案。

Q1: 我的MCP客户端无法连接到服务器,该如何排查?

A1: 连接问题通常有以下几个常见原因:

  1. 服务器路径错误:确保提供了正确的服务器脚本路径,并且该文件确实存在。

  2. 环境问题:确保相应的运行时(Python、Node.js等)已正确安装,并且在PATH中。

  3. 权限问题:确保服务器脚本有执行权限。在Linux/macOS上,可能需要使用chmod +x server_script.py

  4. 依赖缺失:确保服务器所需的所有依赖都已安装。

  5. 端口冲突:如果使用HTTP传输,确保指定的端口没有被其他应用占用。

诊断步骤:

hljs bash
# 1. 手动运行服务器脚本检查是否正常
python server_script.py

# 2. 检查运行时是否正确
python --version
node --version

# 3. 检查日志输出
# 在代码中添加详细日志,或添加环境变量启用调试
export MCP_DEBUG=1

Q2: 工具调用总是返回错误,如何解决?

A2: 工具调用错误通常有以下原因:

  1. 参数格式不正确:确保发送的参数完全符合工具的输入模式(schema)。检查JSON结构、字段名称和数据类型。

  2. 服务器实现问题:服务器可能有bug或未正确处理特定输入。

  3. 超时问题:如果工具执行时间过长,可能会超时。考虑增加超时设置。

  4. 权限问题:服务器可能对某些操作有权限限制。

解决步骤:

hljs python
# 1. 打印完整的工具定义
tools = await client.session.list_tools()
for tool in tools:
    print(f"工具名称: {tool.name}")
    print(f"描述: {tool.description}")
    print(f"输入模式: {json.dumps(tool.inputSchema, indent=2)}")
    print()

# 2. 测试简单调用
try:
    result = await client.session.call_tool("simple_tool", {"simple_param": "test"})
    print("成功:", result)
except Exception as e:
    print("错误:", str(e))

Q3: 如何处理MCP会话中的大量数据?

A3: 处理大量数据时,应考虑以下策略:

  1. 分页和流处理:对于大型结果集,实现分页获取或流式处理。

  2. 数据压缩:考虑在传输层启用压缩。

  3. 批处理请求:合并多个小请求为批处理请求,减少网络往返。

  4. 选择性获取:只获取必要的数据字段,而不是完整记录。

实现示例:

hljs python
async def fetch_large_dataset(self, query, page_size=100):
    """分页获取大型数据集"""
    all_results = []
    page = 1
    has_more = True
    
    while has_more:
        args = {
            "query": query,
            "page": page,
            "page_size": page_size
        }
        
        page_result = await self.session.call_tool("query_data", args)
        
        # 处理本页结果
        results = page_result.content.get("results", [])
        all_results.extend(results)
        
        # 检查是否有更多页
        has_more = page_result.content.get("has_more", False)
        page += 1
        
        # 可选:进度更新
        print(f"已获取 {len(all_results)} 条记录...")
    
    return all_results

Q4: AI模型有时不能正确理解我的意图来调用工具,怎么办?

A4: 改善AI模型与工具调用的协调:

  1. 优化提示语:使用更明确和结构化的提示语,引导模型正确使用工具。

  2. 提供示例:在提示中包含工具使用的示例。

  3. 调整温度参数:降低温度参数(如0.3)使模型输出更确定性。

  4. 使用更强大的模型:如Claude 3.5 Sonnet比早期模型更擅长工具使用。

  5. 验证和引导:在复杂情况下,可以让模型先说明它计划使用哪个工具,然后确认后再执行。

实现示例:

hljs python
async def guided_tool_use(self, query):
    """引导式工具使用"""
    # 第一步:让模型分析并计划
    planning_prompt = f"""
    请分析以下查询,并确定需要使用哪些工具来回答。
    不要直接调用工具,只需列出你计划使用的工具和参数。
    
    查询: {query}
    """
    
    plan = await self.process_query(planning_prompt)
    print("工具使用计划:", plan)
    
    # 第二步:执行计划
    execution_prompt = f"""
    基于以下计划,现在执行适当的工具调用来回答原始查询。
    
    原始查询: {query}
    
    你的计划:
    {plan}
    
    现在请执行这些工具调用并提供最终回答。
    """
    
    result = await self.process_query(execution_prompt)
    return result

Q5: 我的MCP客户端在生产环境中表现不稳定,如何提高可靠性?

A5: 提高生产环境可靠性的策略:

  1. 健壮的错误处理:实现全面的错误捕获和恢复机制。

  2. 重试机制:对临时错误实现智能重试,使用指数退避策略。

  3. 断路器模式:当服务不可用时,暂时停止请求以防止级联故障。

  4. 健康检查:定期检查服务健康状态。

  5. 降级策略:当依赖服务不可用时,提供备用功能。

  6. 全面监控:实现详细的日志和监控,便于排查问题。

  7. 负载测试:在部署前进行负载测试,确保系统在高负载下稳定。

实现示例:

hljs python
class ResilientMCPClient:
    def __init__(self, base_client, max_retries=3, circuit_breaker_threshold=5):
        self.client = base_client
        self.max_retries = max_retries
        self.circuit_breaker_threshold = circuit_breaker_threshold
        self.failures = 0
        self.circuit_open = False
        self.last_failure_time = 0
    
    async def call_tool_resilient(self, tool_name, args):
        """具有弹性的工具调用"""
        # 检查断路器状态
        if self.circuit_open:
            # 检查是否应该重试
            if time.time() - self.last_failure_time > 60:  # 1分钟后半开
                self.circuit_open = False
            else:
                raise CircuitBreakerOpenError("断路器开启,服务暂时不可用")
        
        # 尝试调用,包含重试逻辑
        retry_count = 0
        last_error = None
        
        while retry_count < self.max_retries:
            try:
                return await self.client.session.call_tool(tool_name, args)
            except (ConnectionError, TimeoutError) as e:
                # 临时错误,可以重试
                retry_count += 1
                last_error = e
                
                # 记录失败
                self.failures += 1
                self.last_failure_time = time.time()
                
                # 检查是否应该打开断路器
                if self.failures >= self.circuit_breaker_threshold:
                    self.circuit_open = True
                    raise CircuitBreakerOpenError("达到失败阈值,断路器已开启") from e
                
                # 指数退避
                await asyncio.sleep(2 ** retry_count)
            except Exception as e:
                # 其他错误,不重试
                raise e
        
        # 所有重试都失败
        raise MaxRetriesExceededError("达到最大重试次数") from last_error
    
    def reset_circuit_breaker(self):
        """手动重置断路器"""
        self.failures = 0
        self.circuit_open = False

未来展望:MCP技术的发展趋势

MCP协议作为一项新兴技术,正在快速发展和演进。作为开发者,了解未来趋势对于构建前瞻性应用至关重要。

1. 跨语言和跨平台标准化

随着更多语言SDK的发布,MCP将成为真正的跨语言和跨平台标准,实现"编写一次,随处集成"的愿景。未来可能出现更统一的接口定义和更广泛的语言支持。

2. 更丰富的工具生态系统

预计将涌现大量专业化的MCP服务,覆盖从数据分析到多媒体处理、从IoT控制到企业系统集成等多个领域。这将创造一个丰富的工具生态系统,极大扩展AI应用的能力边界。

3. 增强的安全和隐私特性

随着MCP在企业和敏感领域的应用增加,协议将增强安全和隐私特性,包括更强的认证机制、细粒度的权限控制和端到端加密等。

4. 多模态和实时交互能力

未来的MCP版本可能会增强对多模态输入和输出的支持,使AI模型能够处理和生成文本、图像、音频和视频等多种形式的内容,并支持实时交互。

5. 本地和离线部署选项

为了满足隐私和性能需求,MCP可能会提供更多本地部署和离线工作模式的选项,使应用能够在没有互联网连接的环境中工作。

MCP未来发展趋势

总结与下一步

通过本指南,我们全面介绍了MCP客户端的开发过程,从基础概念到实战案例,涵盖了多种编程语言和应用场景。现在,你已经具备了构建高效、稳定的MCP客户端的技能和知识。

关键收获

  1. MCP基础:了解了MCP的核心概念、架构和工作流程
  2. 多语言实现:掌握了Python、Node.js、Java和.NET等多种语言的MCP客户端开发方法
  3. 高级功能:学习了工具调用、会话管理和安全性等高级特性的实现
  4. 性能优化:掌握了提高MCP客户端性能和可靠性的最佳实践
  5. 实战案例:通过五个典型应用场景,了解了MCP在实际业务中的应用方式

下一步行动

现在,你可以:

  1. 开始实践:基于本指南中的代码示例,构建你自己的MCP客户端
  2. 探索生态系统:尝试连接不同类型的MCP服务,扩展你应用的能力
  3. 贡献社区:参与MCP开源社区,分享你的经验和代码
  4. 持续学习:关注Anthropic的官方文档和更新,跟进MCP协议的最新进展

🔥 开始使用laozhang.ai:别忘了注册laozhang.ai并利用其强大的大模型API能力,为你的MCP客户端注入更智能的AI能力!注册即送免费额度,价格低至官方的20%!

随着MCP生态系统的发展,构建在这一协议之上的应用将变得越来越强大和多样化。现在是进入这一领域的最佳时机,掌握MCP客户端开发技能将为你的AI应用开发之旅带来巨大优势!

【更新日志】持续优化的见证

hljs plaintext
┌─ 更新记录 ──────────────────────────┐
│ 2025-05-15:首次发布完整指南       │
└──────────────────────────────────────┘

推荐阅读