## 如何学习大模型 AI ? 由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。 但是具体到个人,只能说是: **“最先掌握AI的人,将会比较晚掌握AI的

快速上手:实现你的第一个 MCP Client 本文介绍了如何使用 MCP Python SDK 编写一个 MCP 客户端,并集成 LLM 来实现灵活的工具调用和数据处理。通过简单的示例和进阶示例,展示了如何通过标准输入输出(stdio)方式与 MCP 服务器建立连接,并集成 LLM(如通义千问)来实现更复杂的应用场景。 阅读详情

什么是MCP-Client?

MCP-Client是Model Context Protocol(模型上下文协议)架构中的一个重要组件,用于连接AI模型(如Claude、GPT等大型语言模型)与外部数据源、工具和服务的桥梁。

MCP(Model Context Protocol)是由Anthropic公司在2024年底首次提出并开源的一种开放标准协议,旨在解决大语言模型(LLM)与外部世界的连接问题。这一协议的核心价值在于打破了AI模型的"信息孤岛"限制,使模型能够以标准化的方式访问和处理实时数据,显著扩展了大模型的应用场景。

在MCP架构中,有三个关键组件:

  1. MCP服务器(Server):轻量级服务程序,负责对接具体数据源或工具(如数据库、API等),并按照MCP规范提供标准化的功能接口。每个MCP服务器封装了特定的能力,如文件检索、数据库查询等。
  2. MCP客户端(Client):嵌入在AI应用中的连接器,与MCP服务器建立一对一连接,充当模型与服务器之间的桥梁。它负责发现可用服务、发送调用请求、获取结果,并将这些信息传递给AI模型。
  3. 宿主应用(Host):运行LLM的应用程序或环境,如Claude桌面应用、Cursor IDE等。宿主通过集成MCP客户端,使其内部的模型能够调用外部MCP服务器的能力。

MCP-Client的工作原理是基于JSON-RPC 2.0协议,通过标准化的接口与MCP服务器进行通信。它能够自动发现可用的MCP服务器及其提供的工具,并将这些信息以结构化的方式提供给大语言模型,使模型能够理解可用的工具及其功能,从而根据用户需求决定何时何地调用这些工具。

为什么要自写MCP-Client?

自主开发MCP-Client有几个重要的原因和优势:

  1. 定制化需求:市场上的通用MCP客户端(例如:ClaudeDesktop、Cursor、Cline等等)可能无法满足特定业务场景的需求。通过自主开发,可以根据企业或个人的具体需求进行定制,比如添加特定的安全验证、数据过滤、或针对特定领域的优化。
  2. 系统集成:将MCP-Client与现有系统无缝集成。自主开发的MCP-Client可以更好地适配已有的技术栈和架构,减少兼容性问题,提高开发效率。
  3. 数据隐私与安全:对于敏感数据或内部系统,自主开发的MCP-Client可以实现更严格的权限控制和数据保护措施,确保敏感信息不会被未授权访问或泄露。
  4. 性能优化:针对特定用例优化性能。例如,对于需要高频率、低延迟访问的场景,可以通过定制MCP-Client来减少通信开销,提高响应速度。
  5. 扩展功能:实现标准MCP协议之外的增强功能。比如添加高级缓存机制、请求队列管理、负载均衡,或针对特定AI模型优化的上下文处理逻辑。
  6. 控制和可维护性:对于依赖AI能力的核心业务,自主开发的MCP-Client意味着更好的控制能力和可维护性。当需求变化或出现问题时,可以快速进行调整和修复,而不必依赖第三方供应商。
  7. 适配多种AI模型:自主开发的MCP-Client可以设计为同时支持多种不同的大语言模型(如Claude、GPT等),根据任务需求动态选择最适合的模型,提高系统灵活性。
  8. 特殊协议支持:对于需要使用特殊通信协议或数据格式的场景,自主开发可以实现这些非标准需求。
  9. 降低依赖风险:减少对第三方服务的依赖,增强系统的独立性和韧性。如果第三方服务发生变更或中断,自主开发的系统可以更快地适应和调整。
  10. 专业知识沉淀:通过自主开发MCP-Client,团队可以积累AI与外部系统集成的专业知识和经验,这对于长期的AI战略和能力建设非常有价值。

实际上,随着AI应用的深入和普及,越来越多的组织开始认识到,AI基础设施(包括MCP-Client)是一种战略性资产。自主开发这些组件不仅可以获得更好的技术匹配度,还能在竞争中获得差异化优势,尤其是在AI技术对业务至关重要的领域。

MCP协议的开放性恰恰为自主开发MCP-Client提供了可能,使得组织和开发者能够在标准化框架下创建适合自己需求的定制解决方案,同时仍然保持与整个生态系统的互操作性。通过自写MCP-Client,开发者可以充分利用AI大模型的能力,同时保持对系统架构和数据流的完全控制。

MCP-Client编写

工程搭建

在本节实验中,需要大家自己准备一个适配openai协议的大模型API,例如:deepseek V3,Qwen系列,Moonshot月之暗面等等。

为了编写MCP Client,在这里我们直接使用上一节(从0开始实现MCP-Server)中,创建好的工程。

首先创建环境变量.env文件,在该文件中我们放入自己的大模型相关信息:

主要包含3个字段:

  1. OPENAI_API_KEY:大模型的API KEY
  2. BASE_URL:大模型请求地址
  3. MODEL:模型名称

image-20250421221754858

“

这里对模型的种类不限,我使用的是moonshot,大家使用其他大模型均可。

MCP-Prompt

目前支持或深度集成MCP协议的大模型,主要包括:Claude系列和GPT系列等。

国内的大模型供应商对于MCP协议基本上没有做针对性的集成训练,所以在国内使用MCP协议,必须编写结构化的MCP-Prompt,通过system prompt的方式让国内的大模型具备适配MCP协议。

为了编写这个提示词,我使用cloudflare对大模型进行代理,然后对Cursor的MCP请求进行截获并将MCP提示词相关内容保留,其他无关内容删除,得到以下提示词,当然大家也可以自行对这个提示词进行修改,实现自己的定制化。

在工程中创建文件MCP_Prompt.txt,将以下内容放入文件中。

You are an AI assistant, you can help users solve problems, including but not limited to programming, editing files, browsing websites, etc.

====

TOOL USE

You have access to a set of tools that are executed upon the user's approval. You can use one tool per message, and will receive the result of that tool use in the user's response. You use tools step-by-step to accomplish a given task, with each tool use informed by the result of the previous tool use.

# Tool Use Formatting

Tool use is formatted using XML-style tags. The tool name is enclosed in opening and closing tags, and each parameter is similarly enclosed within its own set of tags. Here's the structure:

<tool_name>
<parameter1_name>value1</parameter1_name>
<parameter2_name>value2</parameter2_name>
...
</tool_name>

For example:

<read_file>
<path>src/main.js</path>
</read_file>

Always adhere to this format for the tool use to ensure proper parsing and execution.

# Tools
## use_mcp_tool
Description: Request to use a tool provided by a connected MCP server. Each MCP server can provide multiple tools with different capabilities. Tools have defined input schemas that specify required and optional parameters.
Parameters:
- server_name: (required) The name of the MCP server providing the tool
- tool_name: (required) The name of the tool to execute
- arguments: (required) A JSON object containing the tool's input parameters, following the tool's input schema
Usage:
<use_mcp_tool>
<server_name>server name here</server_name>
<tool_name>tool name here</tool_name>
<arguments>
{
  "param1": "value1",
  "param2": "value2"
}
</arguments>
</use_mcp_tool>

# Tool Use Examples
## Example 1: Requesting to use an MCP tool

<use_mcp_tool>
<server_name>weather-server</server_name>
<tool_name>get_forecast</tool_name>
<arguments>
{
  "city": "San Francisco",
  "days": 5
}
</arguments>
</use_mcp_tool>

## Example 2: Another example of using an MCP tool (where the server name is a unique identifier such as a URL)

<use_mcp_tool>
<server_name>github.com/modelcontextprotocol/servers/tree/main/src/github</server_name>
<tool_name>create_issue</tool_name>
<arguments>
{
  "owner": "octocat",
  "repo": "hello-world",
  "title": "Found a bug",
  "body": "I'm having a problem with this.",
  "labels": ["bug", "help wanted"],
  "assignees": ["octocat"]
}
</arguments>
</use_mcp_tool>

===

MCP SERVERS

The Model Context Protocol (MCP) enables communication between the system and locally running MCP servers that provide additional tools and resources to extend your capabilities.

# Connected MCP Servers

When a server is connected, you can use the server's tools via the `use_mcp_tool` tool, and access the server's resources via the `access_mcp_resource` tool.
<$MCP_INFO$>

===

CAPABILITIES
- You have access to MCP servers that may provide additional tools and resources. Each server may provide different capabilities that you can use to accomplish tasks more effectively.

====

RULES
- MCP operations should be used one at a time, similar to other tool usage. Wait for confirmation of success before proceeding with additional operations.

====

OBJECTIVE

You accomplish a given task iteratively, breaking it down into clear steps and working through them methodically.

1. Analyze the user's task and set clear, achievable goals to accomplish it. Prioritize these goals in a logical order.
2. Work through these goals sequentially, utilizing available tools one at a time as necessary. Each goal should correspond to a distinct step in your problem-solving process. You will be informed on the work completed and what's remaining as you go.
3. Once you've completed the user's task, you must use the attempt_completion tool to present the result of the task to the user. 
4. The user may provide feedback, which you can use to make improvements and try again. But DO NOT continue in pointless back and forth conversations, i.e. don't end your responses with questions or offers for further assistance."

“

在这个提示词中,我设置了一个特殊的标记符<$MCP_INFO$>,该标记符用于后期载入MCP Server及MCP Tool相关工具的描述信息。

Stdio通信协议

stdio 传输方式是最简单的通信方式,通常在本地工具之间进行消息传递时使用。它利用标准输入输出(stdin/stdout)作为数据传输通道,适用于本地进程间的交互。

在这里我们首先以上一节(从0开始实现MCP-Server)中构建的weather MCP Server为例,编写MCP Client向MCP Server进行请求。

编写mcp_client_stdio.py代码如下所示:

import asyncio
from typing import Optional
from contextlib import AsyncExitStack
import json

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

from dotenv import load_dotenv
import os, re
from openai import OpenAI
from lxml import etree

load_dotenv()  # 加载.env文件内容到环境变量中

class MCPClient:
    def __init__(self):
        # Initialize session and client objects
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()
        # 需要提前在.env文件中设置相关环境变量
        self.API_KEY = os.getenv("API_KEY")
        self.BASE_URL = os.getenv("BASE_URL")
        self.MODEL = os.getenv("MODEL")
        # 创建LLM client
        self.client = OpenAI(api_key=self.API_KEY, base_url=self.BASE_URL)
        # 存储历史消息
        self.messages = []
        # 读取提示词模板
        with open("./MCP_Prompt.txt", "r", encoding="utf-8") as file:
            self.system_prompt = file.read()

    async def connect_to_stdio_server(self, mcp_name, command: str, args: list[str], env: dict[str, str]={}):
        """Connect to an MCP server

        Args:
            server_script_path: Path to the server script (.py or .js)
        """
        server_params = StdioServerParameters(
            command=command,
            args=args,
            env=env
        )

        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()
        # 将MCP信息添加到system_prompt
        response = await self.session.list_tools()
        available_tools = ['##' + mcp_name + '\n### Available Tools\n- ' + tool.name + "\n" + tool.description + "\n" + json.dumps(tool.inputSchema) for tool in response.tools]
        self.system_prompt = self.system_prompt.replace("<$MCP_INFO$>", "\n".join(available_tools)+"\n<$MCP_INFO$>")
        tools = response.tools
        print(f"Successfully connected to {mcp_name} server with tools:", [tool.name for tool in tools])

    async def process_query(self, query: str) -> str:
        """Process a query using Claude and available tools"""
        self.messages.append(
            {
                "role": "system",
                "content": self.system_prompt
            }
        )
        self.messages.append(
            {
                "role": "user",
                "content": query
            }
        )

        # Initial Claude API call
        response = self.client.chat.completions.create(
            model=self.MODEL,
            max_tokens=1024,
            messages=self.messages,
        )

        # Process response and handle tool calls
        final_text = []
        content = response.choices[0].message.content
        if'<use_mcp_tool>'notin content:
            final_text.append(content)
        else:
            # 解析tool_string
            server_name, tool_name, tool_args = self.parse_tool_string(content)

            # 执行工具调用
            result = await self.session.call_tool(tool_name, tool_args)
            print(f"[Calling tool {tool_name} with args {tool_args}]")
            print("-"*40)
            print("Server:", server_name)
            print("Tool:", tool_name)
            print("Args:", tool_args)
            print("-"*40)
            print("Result:", result.content[0].text)
            print("-"*40)
            self.messages.append({
                "role": "assistant",
                "content": content
            })
            self.messages.append({
                "role": "user",
                "content": f"[Tool {tool_name} \n returned: {result}]"
            })

            response = self.client.chat.completions.create(
                model=self.MODEL,
                max_tokens=1024,
                messages=self.messages
            )
            final_text.append(response.choices[0].message.content)
        return"\n".join(final_text)
    
    def parse_tool_string(self, tool_string: str) -> tuple[str, str, dict]:
        """
        解析大模型工具调用返回的字符串
        """
        tool_string = re.findall("(<use_mcp_tool>.*?</use_mcp_tool>)", tool_string, re.S)[0]
        root = etree.fromstring(tool_string)
        server_name = root.find('server_name').text
        tool_name = root.find('tool_name').text
        try:
            tool_args = json.loads(root.find('arguments').text)
        except json.JSONDecodeError:
            raise ValueError("Invalid tool arguments")
        return server_name, tool_name, tool_args

    async def chat_loop(self):
        """Run an interactive chat loop"""
        print("\nMCP Client Started!")
        print("Type your queries or 'quit' to exit.")
        self.messages = []
        whileTrue:
            try:
                query = input("\nQuery: ").strip()

                if query.lower() == 'quit':
                    break
                if query.strip() == '':
                    print("Please enter a query.")
                    continue
                response = await self.process_query(query)
                print(response)

            except Exception as e:
                print(f"\nError: {str(e)}")

    async def cleanup(self):
        """Clean up resources"""
        await self.exit_stack.aclose()

async def main():
    client = MCPClient()
    try:
        await client.connect_to_stdio_server('weather', 'python', ['weather.py'])
        await client.chat_loop()
    finally:
        await client.cleanup()

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

“

注意:这里调用的是上一节中编写的weather MCP Server,所以weather.py文件应该和mcp_client_stdio.py文件在同一目录下。

代码执行效果演示:

image-20250421223247549

MCP Server调用成功!

SSE通信协议

SSE 是基于 HTTP 协议的流式传输机制,它允许服务器通过 HTTP 单向推送事件到客户端。SSE 适用于客户端需要接收服务器推送的场景,通常用于实时数据更新。

在这里同样可以以上一节中,我们在公网中搭建的weather MCP SSE Server。

编写代码mcp_client_sse.py如下所示:

import asyncio
from typing import Optional
from contextlib import AsyncExitStack
import json

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

from dotenv import load_dotenv
import os, re
from openai import OpenAI
from lxml import etree

load_dotenv()  # 加载.env文件内容到环境变量中

class MCPClient:
    def __init__(self):
        # Initialize session and client objects
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()
        # 需要提前在.env文件中设置相关环境变量
        self.API_KEY = os.getenv("API_KEY")
        self.BASE_URL = os.getenv("BASE_URL")
        self.MODEL = os.getenv("MODEL")
        # 创建LLM client
        self.client = OpenAI(api_key=self.API_KEY, base_url=self.BASE_URL)
        # 存储历史消息
        self.messages = []
        # 读取提示词模板
        with open("./MCP_Prompt.txt", "r", encoding="utf-8") as file:
            self.system_prompt = file.read()

    async def connect_to_sse_server(self, mcp_name, server_url: str):
        stdio_transport = await self.exit_stack.enter_async_context(sse_client(server_url))
        self.sse, self.write = stdio_transport
        self.session = await self.exit_stack.enter_async_context(ClientSession(self.sse, self.write))

        await self.session.initialize()
        # List available tools
        response = await self.session.list_tools()
        available_tools = ['##' + mcp_name + '\n### Available Tools\n- ' + tool.name + "\n" + tool.description + "\n" + json.dumps(tool.inputSchema) for tool in response.tools]
        self.system_prompt = self.system_prompt.replace("<$MCP_INFO$>", "\n".join(available_tools)+"\n<$MCP_INFO$>\n")
        tools = response.tools
        print(f"Successfully connected to {mcp_name} server with tools:", [tool.name for tool in tools])

    async def process_query(self, query: str) -> str:
        """Process a query using Claude and available tools"""
        self.messages.append(
            {
                "role": "system",
                "content": self.system_prompt
            }
        )
        self.messages.append(
            {
                "role": "user",
                "content": query
            }
        )

        # Initial Claude API call
        response = self.client.chat.completions.create(
            model=self.MODEL,
            max_tokens=1024,
            messages=self.messages,
        )

        # Process response and handle tool calls
        final_text = []
        content = response.choices[0].message.content
        if'<use_mcp_tool>'notin content:
            final_text.append(content)
        else:
            # 解析tool_string
            server_name, tool_name, tool_args = self.parse_tool_string(content)

            # 执行工具调用
            result = await self.session.call_tool(tool_name, tool_args)
            print(f"[Calling tool {tool_name} with args {tool_args}]")
            print("-"*40)
            print("Server:", server_name)
            print("Tool:", tool_name)
            print("Args:", tool_args)
            print("-"*40)
            print("Result:", result.content[0].text)
            print("-"*40)
            self.messages.append({
                "role": "assistant",
                "content": content
            })
            self.messages.append({
                "role": "user",
                "content": f"[Tool {tool_name} \n returned: {result}]"
            })

            response = self.client.chat.completions.create(
                model=self.MODEL,
                max_tokens=1024,
                messages=self.messages
            )
            final_text.append(response.choices[0].message.content)
        return"\n".join(final_text)
    
    def parse_tool_string(self, tool_string: str) -> tuple[str, str, dict]:
        """
        解析大模型工具调用返回的字符串
        """
        tool_string = re.findall("(<use_mcp_tool>.*?</use_mcp_tool>)", tool_string, re.S)[0]
        root = etree.fromstring(tool_string)
        server_name = root.find('server_name').text
        tool_name = root.find('tool_name').text
        try:
            tool_args = json.loads(root.find('arguments').text)
        except json.JSONDecodeError:
            raise ValueError("Invalid tool arguments")
        return server_name, tool_name, tool_args

    async def chat_loop(self):
        """Run an interactive chat loop"""
        print("\nMCP Client Started!")
        print("Type your queries or 'quit' to exit.")
        self.messages = []
        whileTrue:
            try:
                query = input("\nQuery: ").strip()

                if query.lower() == 'quit':
                    break
                if query.strip() == '':
                    print("Please enter a query.")
                    continue
                response = await self.process_query(query)
                print(response)

            except Exception as e:
                print(f"\nError: {str(e)}")

    async def cleanup(self):
        """Clean up resources"""
        await self.exit_stack.aclose()

async def main():
    client = MCPClient()
    try:
         await client.connect_to_sse_server('weather_sse', 'http://47.113.225.16:8000/sse')
        await client.chat_loop()
    finally:
        await client.cleanup()

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

执行效果演示:

image-20250421223848425

同样可以成功调用MCP SSE Server。

“

大家可以直接调用我部署好的MCP SSE Server,

为了方便大家学习,这里可以直接使用的部署好的服务http://47.113.225.16:8000/sse来进行测试。当然也鼓励大家换成其他的服务尝试。

采用配置文件进行加载

经过前面的实验,我们现在已经可以通过自己编写的MCP Client连接任意MCP Server,包括stdio和sse通信协议,但是都只连接了一个MCP Server。用过Cursor或其他MCP Client应用的同学应该很清楚,他们是通过一个JSON配置文件去加载多个MCP Server,那么我们自己编写的MCP Client能否达到这个效果呢?

当然可以,接下来的实验我们就一起来编写相关代码,实现这个需求。

首先,我们定义自己的JSON文件协议,例如:

{
    "mcpServers": {
      "weather-sse": {
        "isActive": true,
        "type": "stdio",
        "command": "python",
        "args": [
          "weather.py"
        ],
        "name": "weather-sse",
        "env": {}
      },
      "amap-amap-sse": {
        "isActive": true,
        "type": "sse",
        "url": "https://mcp.amap.com/sse?key={高德API KEY}",
        "name": "amap-amap-sse"
      }
    }
  }

“

注意:{高德API KEY}大家可以去高德官网注册账号,可以免费获取。

字段意义如下所示:

  1. 公共字段:

    • isActive:用于控制该MCP Server是否被激活。
    • type:MCP Server的类型,取值为stdio或sse
    • name:MCP Server别名。
  2. stdio相关字段:

    • command:命令名称。
    • args:参数列表
    • env:环境变量字典
  3. sse相关参数:

    • url:SSE MCP Server服务地址。

编写mcp_client_mix.py文件,内容如下所示:

import asyncio
from typing import Optional
from contextlib import AsyncExitStack
import json

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

from dotenv import load_dotenv
import os, re
from openai import OpenAI
from lxml import etree

load_dotenv()  # load environment variables from .env

class MCPClient:
    def __init__(self):
        # Initialize session and client objects
        self.session: Optional[ClientSession] = None
        self.exit_stack = AsyncExitStack()
        # 需要提前在.env文件中设置相关环境变量
        self.API_KEY = os.getenv("API_KEY")
        self.BASE_URL = os.getenv("BASE_URL")
        self.MODEL = os.getenv("MODEL")
        self.client = OpenAI(api_key=self.API_KEY, base_url=self.BASE_URL)
        self.sessions = {}
        self.messages = []
        with open("./MCP_Prompt.txt", "r", encoding="utf-8") as file:
            self.system_prompt = file.read()

    async def mcp_json_config(self, mcp_json_file):
        try:
            with open(mcp_json_file, 'r') as f:
                mcp_config: dict = json.load(f)
        except json.JSONDecodeError:
            raise ValueError("Invalid MCP config")
        servers_config: dict = mcp_config.get('mcpServers', {})
        for k, v in servers_config.items():
            try:
                print('-'*50)
                if v.get('isActive', False) == False:
                    continue
                mcp_name = v.get('name', k)
                mcp_type: str = v.get('type', 'stdio')
                if mcp_type.lower() == 'stdio':
                    command = v.get('command', None)
                    args = v.get('args', [])
                    env = v.get('env', {})
                    if command isNone:
                        raise ValueError(f'{mcp_name} command is empty.')
                    if args == []:
                        raise ValueError(f'{mcp_name} args is empty.')
                    await self.connect_to_stdio_server(mcp_name, command, args, env)
                elif mcp_type.lower() == 'sse':
                    server_url = v.get('url', None)
                    if server_url isNone:
                        raise ValueError(f'{mcp_name} server_url is empty.')
                    await self.connect_to_sse_server(mcp_name, server_url)
                else:
                    raise ValueError(f'{mcp_name} mcp type must in [stdio, sse].')
            except Exception as e:
                print(f"Error connecting to {mcp_name}: {e}")

    async def connect_to_stdio_server(self, mcp_name, command: str, args: list[str], env: dict[str, str]={}):
        """Connect to an MCP server

        Args:
            server_script_path: Path to the server script (.py or .js)
        """
        server_params = StdioServerParameters(
            command=command,
            args=args,
            env=env
        )

        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))
        self.sessions[mcp_name] = self.session

        await self.session.initialize()
        # 将MCP信息添加到system_prompt
        response = await self.session.list_tools()
        available_tools = ['##' + mcp_name + '\n### Available Tools\n- ' + tool.name + "\n" + tool.description + "\n" + json.dumps(tool.inputSchema) for tool in response.tools]
        self.system_prompt = self.system_prompt.replace("<$MCP_INFO$>", "\n".join(available_tools)+"\n<$MCP_INFO$>")
        tools = response.tools
        print(f"Successfully connected to {mcp_name} server with tools:", [tool.name for tool in tools])

    async def connect_to_sse_server(self, mcp_name, server_url: str):
        """Connect to an MCP server

        Args:
            server_script_path: Path to the server script (.py or .js)
        """
        stdio_transport = await self.exit_stack.enter_async_context(sse_client(server_url))
        self.sse, self.write = stdio_transport
        self.session = await self.exit_stack.enter_async_context(ClientSession(self.sse, self.write))
        self.sessions[mcp_name] = self.session

        await self.session.initialize()
        # List available tools
        response = await self.session.list_tools()
        available_tools = ['##' + mcp_name + '\n### Available Tools\n- ' + tool.name + "\n" + tool.description + "\n" + json.dumps(tool.inputSchema) for tool in response.tools]
        self.system_prompt = self.system_prompt.replace("<$MCP_INFO$>", "\n".join(available_tools)+"\n<$MCP_INFO$>\n")
        tools = response.tools
        print(f"Successfully connected to {mcp_name} server with tools:", [tool.name for tool in tools])

    async def process_query(self, query: str) -> str:
        """Process a query using Claude and available tools"""
        self.messages.append(
            {
                "role": "system",
                "content": self.system_prompt
            }
        )
        self.messages.append(
            {
                "role": "user",
                "content": query
            }
        )

        # Initial Claude API call
        response = self.client.chat.completions.create(
            model=self.MODEL,
            max_tokens=1024,
            messages=self.messages,
        )

        # Process response and handle tool calls
        final_text = []
        content = response.choices[0].message.content
        if'<use_mcp_tool>'notin content:
            final_text.append(content)
        else:
            # 解析tool_string
            server_name, tool_name, tool_args = self.parse_tool_string(content)

            # 执行工具调用
            result = await self.sessions[server_name].call_tool(tool_name, tool_args)
            print(f"[Calling tool {tool_name} with args {tool_args}]")
            print("-"*40)
            print("Server:", server_name)
            print("Tool:", tool_name)
            print("Args:", tool_args)
            print("-"*40)
            print("Result:", result.content[0].text)
            print("-"*40)
            self.messages.append({
                "role": "assistant",
                "content": content
            })
            self.messages.append({
                "role": "user",
                "content": f"[Tool {tool_name} \n returned: {result}]"
            })

            response = self.client.chat.completions.create(
                model=self.MODEL,
                max_tokens=1024,
                messages=self.messages
            )
            final_text.append(response.choices[0].message.content)
        return"\n".join(final_text)
    
    def parse_tool_string(self, tool_string: str) -> tuple[str, str, dict]:
        tool_string = re.findall("(<use_mcp_tool>.*?</use_mcp_tool>)", tool_string, re.S)[0]
        root = etree.fromstring(tool_string)
        server_name = root.find('server_name').text
        tool_name = root.find('tool_name').text
        try:
            tool_args = json.loads(root.find('arguments').text)
        except json.JSONDecodeError:
            raise ValueError("Invalid tool arguments")
        return server_name, tool_name, tool_args

    async def chat_loop(self):
        """Run an interactive chat loop"""
        print("\nMCP Client Started!")
        print("Type your queries or 'quit' to exit.")
        self.messages = []
        whileTrue:
            try:
                query = input("\nQuery: ").strip()

                if query.lower() == 'quit':
                    break
                if query.strip() == '':
                    print("Please enter a query.")
                    continue
                response = await self.process_query(query)
                print(response)

            except Exception as e:
                print(f"\nError: {str(e)}")

    async def cleanup(self):
        """Clean up resources"""
        await self.exit_stack.aclose()

async def main():
    client = MCPClient()
    try:
        mcp_config_file = './mcp.json'
        await client.mcp_json_config(mcp_config_file)
        await client.chat_loop()
    finally:
        await client.cleanup()

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

演示效果如下所示:

image-20250421230528033

image-20250421230615331

可以看到,两个工具都可以成功调用。

值得进一步优化的小建议

在本节中,我们已经实现了通过MCP配置文件,加载所有的MCP Server,并且经过验证所有的MCP Server工具都可以成功调用。

但是,现在的版本无法完成工具之前进行相互调用,无法通过用户的需求调用多个工具配置完成用户问题的解答,基于此大家可以自行修改现有代码,实现的方式不难,大家可以自己动手实操一下。

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范
  • …

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署
  • …

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建
  • …

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案
  • …

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传优快云,朋友们如果需要可以微信扫描下方优快云官方认证二维码免费领取【保证100%免费】

在这里插入图片描述

【MCP】从0到1实现一个MCP Client MCP Client(Model Context Protocol Client)是模型上下文协议(MCP)架构中的核心组件,负责连接AI模型(如Claude、GPT等)与外部数据源或工具服务 阅读详情

相关推荐

MCP客户端Client开发

打开client.py文件编写代码,可以用记事本、notepad++等,不过建议用一款编程软件,这样可以提升代码编写效率,作者采用vscode。创建项目和创建虚拟环境,已经在上篇中介绍过了,这里不做详细介绍,仅仅列出相关命令。组合上述代码,运行结果如下,这样一个简单的连接AI客户端就实现好了 ^_^将上述代码组合,一个简单的客户端就开发好了!注:MODEL可以更换为DeepSeek模型或者其他或者本地模型。至此客户端和服务端实现完成,是不是不是很难 ^_^执行上述命令创建好了项目并且激活了虚拟环境。

haoswich的专栏 2050

必看!SpringAI轻松构建MCP Client-Server架构

MCP 是 Model Context Protocol,模型上下文协议,它是由 Anthropic(Claude 大模型母公司)提出的开放协议,用于大模型连接外部“数据源”的一种协议。是通过 Spring Boot 集成扩展了 MCP 的 Java SDK(开发工具),它同时提供了 Spring Boot 客户端和服务器的启动器,方便使用 Spring AI MCP 快速开发 AI 应用程序。

磊哥聊Java 7832

STM32寄存器级电机驱动:DRV8833 H桥与PWM调速原理

电机驱动是嵌入式控制系统的核心基础能力,其本质是微控制器通过数字信号精确控制功率器件的开关时序。理解H桥电路结构、反电动势防护机制及PWM调制原理,是实现可靠直流电机控制的前提。DRV8833作为典型双H桥驱动芯片,支持快衰减与慢衰减两种PWM调速模式,分别对应不同的电流泄放路径与动态响应特性。在STM32平台上,需结合时钟树配置、GPIO复用、定时器寄存器(PSC/ARR/CCR)精确计算,将抽象的转速需求转化为可执行的硬件操作。该技术广泛应用于智能小车、机器人关节、工业定位系统等实时运动控制场景,是掌握

weixin_42613017的博客 679

从0手撕代码搭建MCP Client与Server!详解DeepSeek、ollama、vLLM接入MCP实战!

本期内容详解学习MCP必备技术基础,讲解MCP客户端、服务器开发方法及二者接入流程等等。

fufan_LLM的博客 2万+

头歌工程实训答案-机器学习篇之手写体识别篇

第2关:激活函数'''x:负无穷到正无穷的实数'''if x<=0:return 0else:return x#***第3关:反向传播算法import os。

m0_71537260的博客 2518

MWORKS 2025a电气模型库实战:手把手教你搭建全桥LLC电路(附避坑指南)

本文详细介绍了如何使用MWORKS 2025a电气模型库搭建全桥LLC电路,包括环境准备、电路拓扑构建、参数优化及故障诊断。通过实战案例和避坑指南,帮助电源工程师高效设计谐振转换器,提升转换效率至98%以上。文章特别强调了Modelica模型库在电气系统建模中的关键作用。

s8t9u0v1w的博客 603

如何系统的从0到1学习大模型?相关书籍及课程那些比较好?

大模型这个概念我是从去年这时候才了解到的,在不知道大模型之前,我甚至以为chatGPT和大模型就是同一个东西,是可以划等号的。直到国内的AI产品一茬又一茬的冒出来,我才在使用的过程中逐渐对大模型这个概念有了认识。说白了,chatGPT只是大模型的一个小小的知识范围,是一个更具体的概念,是利用大模型技术实现的聊天机器人,专注于自然语言理解和生成。而大模型是一个广泛的概念,涵盖了所有参数众多、能够执行复杂任务的机器学习模型。

m0_71745484的博客 1091

Linux系统下SAPGUI安装包选择与避坑指南

本文详细介绍了在Linux系统下选择和安装SAPGUI安装包的策略与避坑指南。重点解析了不同版本安装包的关键区别,特别是Linux版必须包含linux-lib.jar和linux64-lib.jar文件,避免误用Mac或Windows版导致的兼容性问题。文章还提供了针对Ubuntu、RHEL等不同Linux发行版的安装实战指南,以及常见报错的解决方案,帮助用户顺利完成SAPGUI的安装与配置。

weixin_28366353的博客 675

为什么要学习AI大模型呢?它的前景很好吗?适合什么样的人群学习?

为什么要学习AI大模型?随着人工智能技术的飞速发展,AI大模型已经成为推动社会进步和产业升级的重要力量。学习AI大模型不仅能够帮助个人在技术领域获得竞争优势,还能为企业和社会创造巨大的价值。以下是学习AI大模型的一些重要原因:市场需求增长随着各行各业对智能化需求的增加,AI大模型的需求也在快速增长。从自然语言处理、计算机视觉到语音识别,AI大模型的应用范围极为广泛。无论是互联网巨头还是初创公司,都在积极招募具备AI大模型开发和应用能力的人才。高薪就业机会。

m0_71745484的博客 1120

汇率波动率建模实战:从GARCH到EGARCH的金融时间序列分析

在金融时间序列分析中,波动率建模是量化市场风险的核心技术。其基本原理在于捕捉金融资产收益率序列中存在的波动聚集、尖峰厚尾等典型特征。通过建立条件异方差模型,如GARCH及其扩展模型,可以动态估计和预测未来波动率,这对于资产定价、风险管理和投资决策具有重要价值。在金融工程领域,该技术广泛应用于外汇、股票和衍生品市场。本文以汇率波动率建模为具体场景,详细阐述了如何使用Python中的arch库,从数据预处理、模型选型(包括GARCH、EGARCH等)、参数估计到样本外预测评估的全流程实践,并深入探讨了模型在应对

weixin_32629853的博客 371

PyTorch实战(30)——使用TorchScript和ONNX导出通用PyTorch模型

在本节中,我们将深入探讨使用 TorchScript 导出 PyTorch 模型。通过序列化,TorchScript 使模型与 Python 生态系统独立,从而使得模型可以在其他环境中加载,例如基于 C++ 的环境。我们还跨越 Torch 框架与 Python 生态的边界,研究机器学习通用开放格式 ONNX,该技术能帮助我们将 PyTorch 训练的模型导出至非 PyTorch 甚至非 Python 环境。

盼小辉丶的博客 3528

别再到处找了!Cursor AI提示词模板大全来了,附上手指南,效率翻倍!

本文提供了AI提示词工程的高效模板和使用指南,主要包括:1. 代码生成与重构模板(登录页面开发、代码解释优化等);2. 大模型AI学习路径,分为初阶应用、高阶应用、模型训练、商业闭环四个阶段;3. 大模型行业现状分析,指出AI岗位缺口大、薪资高,掌握AI工具可提升47%生产效率;4. 免费学习资源包(提示词模板库、RAG系统指南、智能体开发教程等)。强调率先掌握AI技术将获得显著竞争优势,并提供了系统的90天学习规划。

2401_85390073的博客 6579

从0到1带大家搭建spring cloud alibaba 微服务大型应用框架(十一)spring-boot-admin 监控篇(2)springcloud 集成spring boot admin

从0到1 手把手搭建spring cloud alibaba 微服务大型应用框架(十一)spring-boot-admin 监控篇(2)springcloud 集成spring boot admin spring-boot-admin 服务端创建与集成入nacos spring-boot-admin 查看日志

峡谷电光马仔的博客 1382

老IT人亲测:Claudecode让编程小白也能高效开发大模型应用!

本文是一位近20年IT经验的老IT人分享的AI辅助编程工具Claudecode使用教程。文章详细介绍了Claudecode的安装、配置方法,并通过开发一个H5五子棋小游戏展示了其实际应用。Claudecode能够根据自然语言描述自动生成高质量代码,非常适合编程能力较弱但有开发需求的IT人士,可显著提高编程效率。

WANGJUNAIJIAO的博客 1583

锁的艺术:Java并发中的常用锁策略与实践

对java锁相关内容进行整理分析:乐观锁 VS 悲观锁+自旋锁 VS 适应性自旋锁+无锁 VS 偏向锁 VS 轻量级锁 VS 重量级锁+公平锁 VS 非公平锁+可重入锁 VS 非可重入锁+独享锁 VS 共享锁

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 171万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

GPT王者归来,CSND独家揭秘!打造AI大模型学习盛宴,全网最强AI实战教程

5月14日,一场不到30分钟的发布会,再次引爆AI行业巨变。OpenAI正式发布GPT-4o,在新的大模型的支撑下,ChatGPT 的交互体验,让全球人震惊。它具备文本、图片、视频和语音能力,能够实现更自然的人机交互。✅ 做题高手:演示如何给线性方程 3X+1=4 的求解提供帮助,它能够一步步贴心地引导并给出正确答案。✅ 现场编码:程序员关心的编码难题是真正的考验,不过,GPT-4o三下五除二的功夫,它都能轻松解决。

m0_71745484的博客 590

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

小白也能上手!使用Coze创建大模型个人知识库智能体

本文介绍了在Coze平台创建个人知识库智能体的完整流程。通过搭建工作流实现文件上传、文本处理和知识库写入功能,解决大模型回答泛泛的问题。详细讲解了智能体创建、工作流节点设计(包括选择器、文件读取、文本处理等关键步骤)以及人设设置。最终构建的智能体能够将个人专业知识结构化存储,生成差异化洞见,提升AI回答的专业性和准确性。文章还提供了学习AI大模型的相关资源获取方式。

m0_59162248的博客 2195

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

一站式攻略:零基础玩转AI大模型,助你快速成为技术大牛!

一.初聊大模型1.为什么要学习大模型?在学习大模型之前,你不必担心自己缺乏相关知识或认为这太难。我坚信,只要你有学习的意愿并付出努力,你就能够掌握大模型,并能够用它们完成许多有意义的事情。在这个快速变化的时代,虽然新技术和概念不断涌现,但希望你能静下心来,踏实地学习。一旦你精通了某项技术,你就能够用它来实现自己的目标,甚至可能找到理想的工作或完成具有挑战性的项目。在众多的技术中,大模型因其强大的功能和广泛的应用而备受推崇。那么,为什么要学习大模型呢?

m0_71745484的博客 520

让GPT-4o测测你是E人还是I人,prompt 绝了!

OpenAI 发布了 GPT-4o,同时也支持接口访问。接口的好处是不用登录官网也能使用。使用GPT-4o之前,可以用下面的问题三连,进行验证这次的任务,需要让GPT-4o给我们出一些列测试题,我们来作答。每次GPT只出一道题,答完之后,再出下一道,全部答完后,GPT 根据作答结果进行性格分析。整个任务我们用一条 Prompt 来完成,核心部分为:定义一个的任务让GPT明白要循环调用任务为用户出题记录整体完成度,给用户完成度的预期记录用户每次作答的结果,以便最后进行性格分析。

m0_59235945的博客 1173

2024年大模型学习宝典:小白进阶至高手的全程指导

前言随着人工智能技术的迅猛发展,大模型(Large Models)已成为这一领域的新宠。从GPT系列到BERT,再到各类变体,大模型以其强大的能力吸引了无数开发者和研究者的目光。那么,作为一个零基础的学习者,如何快速入门并精通大模型技术呢?本文将为你提供一份详尽的学习指南。一、大模型基础概念在开始深入学习之前,我们需要了解大模型的基本概念和特点。大模型通常指的是参数量巨大、结构复杂的神经网络模型,它们能够处理海量的数据,并具备强大的学习和推理能力。二、学习路径规划。

m0_71745484的博客 653

我可真厉害,3分钟让你成为AI高手:提示词(prompt)制作及调优(免费教你,别再被割了)

学会这个方法,让你秒省788!今天就再来用实操演示一遍地址:https://tongyi.aliyun.com/qianwen/把复制的提示词粘贴到输入框内拖动到最上边,把""内的,改成你想要生成的提示词的简单描述比如牛叔这里要生成一个:儿童睡前故事创作专家然后点这样我们就获得了初版的提示词。点击按钮,新建一个对话进行调试然后点击等待初始化完成后,输入一个故事主题比如牛叔这里输入的:七个小矮人和小红帽的故事点击这样我们就获得了一个儿童睡前故事要调优,首先。

python1222_的博客 3651

如何使用 Cursor + AI 搞定产品原型图?

UI 原型图是设计师和开发者用来展示产品界面外观和功能的视觉模型。它就像是软件或网站的"草图",帮助团队在开发前先看到产品的样子。UI 原型图可以有不同的精细度,从简单的线框图到高保真的交互式设计。创建一个好的 UI 原型图通常需要设计技能和专业工具,这对很多开发者来说可能是个挑战。好了,模版和方法都告诉你了,剩下的就看你们的发挥了。大模型算是目前当之无愧最火的一个方向了,算是新时代的风口!有小伙伴觉得,作为新领域、新方向人才需求必然相当大,与之相应的人才缺乏、人才竞争自然也会更少,

2301_81888214的博客 1562

【100个AI核心概念】结构化提示词

我们更大模型对话时的任何输入都称为提示词prompt,哪怕是一句简单的“你好”。基于习惯,通常我们会输入一整段话,在认为较简单时这没有问题,但如果任务复杂,提示词很长,就需要用到结构化提示词技巧。通过使用分隔符(如“–”、“###”等),可以清晰地区分不同部分的内容,比如问题和背景信息、不同的问题点等。这种清晰的结构使得模型更容易理解prompt的不同组成部分,从而提高回答的准确性和相关性。分隔符帮助模型区分和识别信息的不同层次和类别,比如区分指令、问题、背景信息等。

m0_59164520的博客 2822

收藏!大模型学习路线图:从零基础到应用开发,5本书带你轻松入门!

文章提供大模型学习路线图,推荐5本循序渐进书籍:Python编程、深度学习、ChatGPT原理、大模型应用开发和LangChain编程。这些资源专为初学者设计,无需四处寻找其他学习资料,按顺序学习即可掌握大模型知识和应用开发能力,对提升技术能力和职场竞争力至关重要。

WANGJUNAIJIAO的博客 603
上一篇: Anthropic:推理模型心口不一,链式思考是否可信?
下一篇: 教程|通义Qwen 3 +Milvus,混合推理模型才是优化RAG成本的最佳范式
Python_金钱豹
博客等级 码龄5年 1万+粉丝 2835原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值