*【HM-LC】LangChain MCP详解:核心概念、外部服务连接与自定义服务

MCP (M odel C ontext Protocol) 是由 Anthropic 推出的开放标准,用于便捷的将AI应用连接外部系统。

在没有MCP的时候,必须手动定义工具,用工具实现文件操作、web搜索、查询航班、查询天气等功能,从而让AI连接外部系统。

这就存在两个问题:

  • 不同Agent可能有同样的tool需求,每次都重复定义,复用性差
  • 全世界有各种不同的服务,不同服务接口不同,定义Tool非常麻烦

MCP就像是AI世界的USB接口协议:

  • 所有外部服务提供者都可以遵循MCP协议提供Tool,分享自己的Tool服务
  • AI应用基于MCP协议对接任意遵循MCP的外部服务,无需自己定义Tool

这样一来就解决了重复定义工具的复用性问题、以及对接全世界各种公共服务的问题。

一、MCP核心概念

在MCP中有三个核心概念:

概念 说明
MCP Server 提供MCP服务的应用,可以是远程服务,也可以是本地服务
MCP Client 连接到MCP服务器,读取MCP信息(特别是Tool信息),供Host使用
MCP Host 协调和管理多个MCP Client的AI应用,比如LangChain的Agent

例如,一个AI应用,也就是MCP Host,它需要三个功能:

  • 文件操作
  • 数据库操作
  • Sentry远程服务

此时,它可以定义3个不同的MCP Client,分别对接3个MCP Server,包含一个操作本地文件的MCP、一个访问数据库的MCP、一个访问Sentry服务的MCP

MCP Client 与 MCP Server之间有两种通信协议:

  • stdio
  • streamable_http

stdio就是标准输入输出,MCP Client运行时,分两种情况:

  • 外部服务:Client会把这个MCP服务的脚本下载到本地,然后作为一个子进程运行。
  • 本地服务:Client会把本地脚本直接加载,作为一个子进程运行

也就是说,stdio模式中,MCP Client 和 MCP Server之间的通信就是进程通信,没有网络延迟。

streamable_http其实就是可以用event stream来发送数据的http模式,本质还是Server Send Event,也就是SSE。也就是说MCP client通过发送http请求与MCP server交互。因此存在一定的网络延迟。

详细的MCP说明可以参考Anthropic公司的MCP官方文档:

https://modelcontextprotocol.io/docs/getting-started/intro

有关通信协议可以查看:

https://modelcontextprotocol.io/specification/2025-11-25/basic/transports

LangChain本身实现了对MCP的支持,本节我们就来学习如何在LangChain中使用MCP

二、连接外部MCP服务

很多提供云服务的公司都提供了MCP服务,例如:

  • Amap Maps : 高德地图提供的MCP
  • Filesystem : 可以操作文件系统的MCP
  • Time : 查询当前时间的MCP服务
  • Kiwi : 查询航班、预定航班的MCP服务
  • ...

大家可以在https://mcp.so/zh/搜索各种MCP服务(国际的比较多):

https://mcp.so/zh/

MCP.so

Discover useful MCP servers and clients

也可以在魔塔社区搜索MCP服务(国产的比较多):

https://modelscope.cn/mcp

ModelScope - MCP 广场

聚合优质MCP资源,拓展智能边界!

找好自己想要使用的MCP服务后,就可以用LangChain来对接了。

首先,我们需要安装LangChain的MCP client依赖库:

Plain 复制代码
uv add langchain-mcp-adapters

接下来,就可以用LangChain对接MCP服务,获取其提供的工具,创建Agent了。

接下来,我们以两个MCP服务为例来介绍LangChain对接MCP服务的方式:

  • Time MCP :基于stdio通信
  • Kiwi MCP : 基于Streamable http通信

2.1 Time MCP服务

Time是一个提供时间和时区转换功能的MCP服务。此服务使LLM能够获取当前时间信息,并使用 IANA 时区名称执行时区转换,同时具备自动检测系统时区的功能。

查看Time MCP的介绍页面,可以看到其介绍,以及集成方式:

https://mcp.so/zh/server/time/modelcontextprotocol

MCP Server(MCP 服务器)

最大的 MCP Server(MCP 服务器)集合,包括优秀的 MCP Server(MCP 服务器)和 Claude MCP 集成。搜索和发现 MCP Server(MCP 服务器)以增强您的 AI 能力。

需要注意的是,Time MCP是基于stdio的通信方式,也就是把这个MCP服务的脚本下载到本地,然后作为一个子进程运行。

其中,MCP脚本下载的方式取决于配置中的command,常见的有两种:

  • npx : 基于node.js的包管理工具
  • uvx : 基于uv(python的uv工具)的包管理工具

因此,你的本地环境必须支持npx、uvx命令

另外,在LangChain中除了基本的服务器配置,还必须设置一个transport参数,指定MCP服务的通信方式,有两个可选值:

  • stdio
  • http或者 streamable_http

与标准的mcp参数相比,LangChain的配置存在一些差异:

JSON 复制代码
{
  "mcpServers": {
    "time": {
      "command": "uvx",
      "args": [
        "mcp-server-time",
        "--local-timezone=America"
      ]
    }
  }
}
JSON 复制代码
client = MultiServerMCPClient(
    {
        "time": {
            "transport": "stdio",
            "command": "uvx",
            "args": [
                "mcp-server-time",
                "--local-timezone=A"
              ]
        }
    }
)

注意 :如果是在Notebook运行,可能出现事件循环错误,需要加一段判断逻辑:

Python 复制代码
import sys
import asyncio

# Fix for Windows issues in Jupyter notebooks
if sys.platform == "win32":
    # 1. Use ProactorEventLoop for subprocess support
    if not isinstance(asyncio.get_event_loop_policy(), asyncio.WindowsProactorEventLoopPolicy):
        asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())

    # 2. Redirect stderr to avoid fileno() error when launching MCP servers
    if "ipykernel" in sys.modules:
        sys.stderr = sys.__stderr__

示例代码(以下代码必须在Notebook中运行):

Python 复制代码
# 1.加载环境变量
from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage
from langchain_mcp_adapters.client import MultiServerMCPClient

load_dotenv()

# 2.初始化模型
model = init_chat_model(
    model="deepseek-v4-flash",
    extra_body={"thinking": {"type": "disabled"}}
)

# 3.定义工具,用MCP获取工具
# 3.1.定义mcp client
client = MultiServerMCPClient(
    {
        "time": {
            "transport": "stdio",
            "command": "uvx",
            "args": [
                "mcp-server-time",
                "--local-timezone=Asia/Shanghai"
            ]
        }
    }
)

# 3.2.用client拉取tool
# 注意MultiServerMCPClient是异步的,结果都是协程对象,需要await
tools = await client.get_tools()


# 4.创建Agent,绑定模型和工具
agent = create_agent(
    model=model,
    tools=tools
)

# 5.由于MCP的Tool是异步的,所以必须用ainvoke调用Agent,是异步调用
response = await agent.ainvoke(
    {"messages": [HumanMessage("现在是什么时间")]}
)
print(response)

结果:

JSON 复制代码
================================ Human Message =================================

现在几点了?
================================== Ai Message ==================================

好的,我先获取一下当前的时间。
Tool Calls:
  get_current_time (call_00_LEeOqXUsKTiAo4abwEjn6951)
 Call ID: call_00_LEeOqXUsKTiAo4abwEjn6951
  Args:
    timezone: Asia/Shanghai
================================= Tool Message =================================
Name: get_current_time

[{'type': 'text', 'text': '{\n  "timezone": "Asia/Shanghai",\n  "datetime": "2026-05-12T10:47:13+08:00",\n  "day_of_week": "Tuesday",\n  "is_dst": false\n}', 'id': 'lc_ccf2b9d8-76e4-491e-839a-e3a1d703f7b8'}]
================================== Ai Message ==================================

现在是 **2026年5月12日 星期二 上午10:47**(北京时间,UTC+8)。

2.2 Kiwi MCP服务

Kiwi Travel MCP 将 Kiwi.com 的航班搜索功能直接引入到 AI 对话中。支持单程/往返、灵活日期、多名乘客以及所有舱位等级。
注意:

  • Kiwi服务是基于http的通信方式,也就是说MCP client通过发送http请求与MCP server交互,在国内访问存在较大网络延迟。
  • 通常这类外部的MCP服务都是需要收费的,需要申请API key才能使用,而Kiwi是仅有的免费航班搜索服务

查看Kiwi介绍页,可以找到它的使用方式:

https://mcp.so/zh/server/kiwi-travel-mcp/Vytautas Dargis

MCP Server(MCP 服务器)

最大的 MCP Server(MCP 服务器)集合,包括优秀的 MCP Server(MCP 服务器)和 Claude MCP 集成。搜索和发现 MCP Server(MCP 服务器)以增强您的 AI 能力。

示例代码:

Python 复制代码
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
from langchain_core.messages import HumanMessage

# 连接Kiwi MCP服务器
client = MultiServerMCPClient(
    {
        "kiwi-com-flight-search": {
            "transport": "http",
            "url": "https://mcp.kiwi.com"
        }
    }
)

# 注意MultiServerMCPClient是异步的,结果都是协程对象,需要await
tools = await client.get_tools()


agent = create_agent(
    model="deepseek-chat",
    tools=tools,
    system_prompt="You are a travel agent. Help user find best flights. No follow up questions. If the user uses Chinese, use zh-cn as the locale value."
)

response = await agent.ainvoke({
    "messages": [HumanMessage("查一下2026年5月15日晚上从北京飞杭州的航班。")]
})

for message in response["messages"]:
    message.pretty_print()

注意:由于Kiwi中有地域参数(locale),但Tool描述中没说清楚,中文有两种:zh-cn,zh-tw,需要在系统提示词中说明,否则AI默认会传入zh,导致报错。

结果:

JSON 复制代码
================================ Human Message =================================

查一下2026年5月15日晚上从北京飞杭州的航班。
================================== Ai Message ==================================

好的,我来查一下2026年5月15日从北京飞杭州的航班。
Tool Calls:
  search-flight (call_00_pRivmQypfxROSByOOncn2383)
 Call ID: call_00_pRivmQypfxROSByOOncn2383
  Args:
    flyFrom: 北京
    flyTo: 杭州
    departureDate: 15/05/2026
    locale: zh-cn
    curr: CNY
================================= Tool Message =================================
Name: search-flight

[{'type': 'text', 'text': '[\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-14T18:35:00.000Z",\n      "local": "2026-05-15T02:35:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T06:40:00.000Z",\n      "local": "2026-05-15T14:40:00.000"\n    },\n    "totalDurationInSeconds": 43500,\n    "durationInSeconds": 43500,\n    "price": 2064,\n    "deepLink": "https://on.kiwi.com/R6Qfim",\n    "currency": "CNY",\n    "layovers": [\n      {\n        "at": "HKG",\n        "city": "Hong Kong",\n        "cityCode": "HKG",\n        "arrival": {\n          "utc": "2026-05-14T22:10:00.000Z",\n          "local": "2026-05-15T06:10:00.000"\n        },\n        "departure": {\n          "utc": "2026-05-15T04:15:00.000Z",\n          "local": "2026-05-15T12:15:00.000"\n        }\n      }\n    ]\n  },\n  {\n    "flyFrom": "PEK",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-14T23:00:00.000Z",\n      "local": "2026-05-15T07:00:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T01:20:00.000Z",\n      "local": "2026-05-15T09:20:00.000"\n    },\n    "totalDurationInSeconds": 8400,\n    "durationInSeconds": 8400,\n    "price": 2855,\n    "deepLink": "https://on.kiwi.com/gk6lb3",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-14T23:25:00.000Z",\n      "local": "2026-05-15T07:25:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T01:25:00.000Z",\n      "local": "2026-05-15T09:25:00.000"\n    },\n    "totalDurationInSeconds": 7200,\n    "durationInSeconds": 7200,\n    "price": 2997,\n    "deepLink": "https://on.kiwi.com/TaY2gW",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-14T23:30:00.000Z",\n      "local": "2026-05-15T07:30:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T01:30:00.000Z",\n      "local": "2026-05-15T09:30:00.000"\n    },\n    "totalDurationInSeconds": 7200,\n    "durationInSeconds": 7200,\n    "price": 2577,\n    "deepLink": "https://on.kiwi.com/8LKN8m",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PEK",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-14T23:55:00.000Z",\n      "local": "2026-05-15T07:55:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T02:15:00.000Z",\n      "local": "2026-05-15T10:15:00.000"\n    },\n    "totalDurationInSeconds": 8400,\n    "durationInSeconds": 8400,\n    "price": 2855,\n    "deepLink": "https://on.kiwi.com/tXsAO2",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T00:55:00.000Z",\n      "local": "2026-05-15T08:55:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T03:05:00.000Z",\n      "local": "2026-05-15T11:05:00.000"\n    },\n    "totalDurationInSeconds": 7800,\n    "durationInSeconds": 7800,\n    "price": 2567,\n    "deepLink": "https://on.kiwi.com/g1E8T1",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T01:15:00.000Z",\n      "local": "2026-05-15T09:15:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T03:15:00.000Z",\n      "local": "2026-05-15T11:15:00.000"\n    },\n    "totalDurationInSeconds": 7200,\n    "durationInSeconds": 7200,\n    "price": 2577,\n    "deepLink": "https://on.kiwi.com/MBY1DT",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T01:45:00.000Z",\n      "local": "2026-05-15T09:45:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T03:55:00.000Z",\n      "local": "2026-05-15T11:55:00.000"\n    },\n    "totalDurationInSeconds": 7800,\n    "durationInSeconds": 7800,\n    "price": 2567,\n    "deepLink": "https://on.kiwi.com/kxuUqk",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T03:00:00.000Z",\n      "local": "2026-05-15T11:00:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T05:00:00.000Z",\n      "local": "2026-05-15T13:00:00.000"\n    },\n    "totalDurationInSeconds": 7200,\n    "durationInSeconds": 7200,\n    "price": 2577,\n    "deepLink": "https://on.kiwi.com/TEGUnO",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PEK",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T03:55:00.000Z",\n      "local": "2026-05-15T11:55:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T06:15:00.000Z",\n      "local": "2026-05-15T14:15:00.000"\n    },\n    "totalDurationInSeconds": 8400,\n    "durationInSeconds": 8400,\n    "price": 2855,\n    "deepLink": "https://on.kiwi.com/JVoG0m",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T07:55:00.000Z",\n      "local": "2026-05-15T15:55:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T10:15:00.000Z",\n      "local": "2026-05-15T18:15:00.000"\n    },\n    "totalDurationInSeconds": 8400,\n    "durationInSeconds": 8400,\n    "price": 2567,\n    "deepLink": "https://on.kiwi.com/mzeQCO",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PEK",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T10:00:00.000Z",\n      "local": "2026-05-15T18:00:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T12:10:00.000Z",\n      "local": "2026-05-15T20:10:00.000"\n    },\n    "totalDurationInSeconds": 7800,\n    "durationInSeconds": 7800,\n    "price": 2855,\n    "deepLink": "https://on.kiwi.com/OdRGgW",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PKX",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T13:25:00.000Z",\n      "local": "2026-05-15T21:25:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T15:40:00.000Z",\n      "local": "2026-05-15T23:40:00.000"\n    },\n    "totalDurationInSeconds": 8100,\n    "durationInSeconds": 8100,\n    "price": 2567,\n    "deepLink": "https://on.kiwi.com/he76C4",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PEK",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T13:25:00.000Z",\n      "local": "2026-05-15T21:25:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T15:35:00.000Z",\n      "local": "2026-05-15T23:35:00.000"\n    },\n    "totalDurationInSeconds": 7800,\n    "durationInSeconds": 7800,\n    "price": 2855,\n    "deepLink": "https://on.kiwi.com/fpJyFp",\n    "currency": "CNY"\n  },\n  {\n    "flyFrom": "PEK",\n    "flyTo": "HGH",\n    "cityFrom": "Beijing",\n    "cityTo": "Hangzhou",\n    "departure": {\n      "utc": "2026-05-15T14:05:00.000Z",\n      "local": "2026-05-15T22:05:00.000"\n    },\n    "arrival": {\n      "utc": "2026-05-15T16:25:00.000Z",\n      "local": "2026-05-16T00:25:00.000"\n    },\n    "totalDurationInSeconds": 8400,\n    "durationInSeconds": 8400,\n    "price": 2855,\n    "deepLink": "https://on.kiwi.com/RHEvxA",\n    "currency": "CNY"\n  }\n]', 'id': 'lc_dfcd0ae5-f9b9-4a9c-b477-4f0a3e01078c'}]
================================== Ai Message ==================================

好的!以下是2026年5月15日(周五)从北京飞往杭州的航班信息。由于您说"晚上",我特别筛选了下午到晚间出发的航班为您整理如下:

---

### 🌟 最便宜航班(性价比之选)

| 航线 | 时间 | 舱位 | 价格 | 预订链接 |
|------|------|------|:----:|:--------:|
| 北京大兴 PKX → 杭州 HGH(经香港转机) | **05/15 02:35 → 14:40**(12h 05m) | 经济舱 | **¥2,064** | [预订](https://on.kiwi.com/R6Qfim) |

### ⚡ 最短飞行(直飞最快)

| 航线 | 时间 | 舱位 | 价格 | 预订链接 |
|------|------|------|:----:|:--------:|
| 北京大兴 PKX → 杭州 HGH(直飞) | **05/15 07:25 → 09:25**(2h 00m) | 经济舱 | ¥2,997 | [预订](https://on.kiwi.com/TaY2gW) |
| 北京大兴 PKX → 杭州 HGH(直飞) | **05/15 07:30 → 09:30**(2h 00m) | 经济舱 | **¥2,577** | [预订](https://on.kiwi.com/8LKN8m) |
| 北京大兴 PKX → 杭州 HGH(直飞) | **05/15 09:15 → 11:15**(2h 00m) | 经济舱 | **¥2,577** | [预订](https://on.kiwi.com/MBY1DT) |
| 北京大兴 PKX → 杭州 HGH(直飞) | **05/15 11:00 → 13:00**(2h 00m) | 经济舱 | **¥2,577** | [预订](https://on.kiwi.com/TEGUnO) |

### ✈️ 其他可选航班(晚间出发)

| 航线 | 时间 | 舱位 | 价格 | 预订链接 |
|------|------|------|:----:|:--------:|
| 北京首都 PEK → 杭州 HGH(直飞) | **05/15 07:00 → 09:20**(2h 20m) | 经济舱 | ¥2,855 | [预订](https://on.kiwi.com/gk6lb3) |
| 北京首都 PEK → 杭州 HGH(直飞) | **05/15 07:55 → 10:15**(2h 20m) | 经济舱 | ¥2,855 | [预订](https://on.kiwi.com/tXsAO2) |
| 北京大兴 PKX → 杭州 HGH(直飞) | **05/15 08:55 → 11:05**(2h 10m) | 经济舱 | **¥2,567** | [预订](https://on.kiwi.com/g1E8T1) |
| 北京大兴 PKX → 杭州 HGH(直飞) | **05/15 09:45 → 11:55**(2h 10m) | 经济舱 | **¥2,567** | [预订](https://on.kiwi.com/kxuUqk) |
| 北京首都 PEK → 杭州 HGH(直飞) | **05/15 11:55 → 14:15**(2h 20m) | 经济舱 | ¥2,855 | [预订](https://on.kiwi.com/JVoG0m) |
| 北京大兴 PKX → 杭州 HGH(直飞) | **05/15 15:55 → 18:15**(2h 20m) | 经济舱 | **¥2,567** | [预订](https://on.kiwi.com/mzeQCO) |
| 北京首都 PEK → 杭州 HGH(直飞) | **05/15 18:00 → 20:10**(2h 10m) | 经济舱 | ¥2,855 | [预订](https://on.kiwi.com/OdRGgW) |
| 北京大兴 PKX → 杭州 HGH(直飞) | **05/15 21:25 → 23:40**(2h 15m) | 经济舱 | **¥2,567** | [预订](https://on.kiwi.com/he76C4) |
| 北京首都 PEK → 杭州 HGH(直飞) | **05/15 21:25 → 23:35**(2h 10m) | 经济舱 | ¥2,855 | [预订](https://on.kiwi.com/fpJyFp) |
| 北京首都 PEK → 杭州 HGH(直飞) | **05/15 22:05 → 00:25**(2h 20m) | 经济舱 | ¥2,855 | [预订](https://on.kiwi.com/RHEvxA) |

---

### 💡 推荐总结

- **💰 最便宜**:经香港转机的航班仅 **¥2,064**,但耗时较长(约12小时)
- **⚡ 最快**:大兴机场直飞仅需 **2小时**,价格 **¥2,577起**(如07:30出发的航班)
- **🌟 最佳推荐**:如果您想要晚上出发,推荐 **大兴 PKX 21:25→23:40(¥2,567)** 或 **首都 PEK 21:25→23:35(¥2,855)**,都是晚间直飞,到了杭州直接休息!

祝您旅途愉快!🎉 说到杭州,你知道吗?**杭州西湖在2011年被列入世界文化遗产,而著名的"断桥"其实从不断,只是因为冬雪消融时远看桥面像断了一样而得名哦!** 🏔️🌉

说明:Kiwi更擅长搜索国际航班,如果是国内航班更建议大家基于携程官方API开发Tool来实现航班搜索。

另外,有一个替代的国内航班查询MCP服务,地址是:https://mcp.variflight.com/

不过这个服务是收费的,而且价格比较贵,即便是优惠过后也需要0.1元/次。

使用步骤是:

  • 注册账号
  • 申请API Key
  • 接入MCP

代码示例:

Python 复制代码
from langchain_mcp_adapters.client import MultiServerMCPClient

# 连接Kiwi MCP服务器
client = MultiServerMCPClient(
    {
        "VariFlight-Aviation": {
            "transport": "http",
            "url": "https://ai.variflight.com/servers/aviation/mcp/?api_key=您在飞友AI开放平台申请的Key"
        }
    }
)

tools = await client.get_tools()

agent = create_agent(
    model="deepseek-chat",
    tools=tools,
    system_prompt="You are a travel agent. Help user find best flights. No follow up questions."
)

response = await agent.ainvoke({
    "messages": [HumanMessage("查一下2026年5月15日晚上从北京飞杭州的航班。")]
})

for message in response["messages"]:
    message.pretty_print()

三、自定义MCP服务

在公司内部,不同团队之间也可以把自己团队的服务开发成MCP Server,供其它团队使用。

接下来,我们就学习如何自定义MCP服务。

3.1 创建简单的MCP服务器

自定义MCP最简单的方式就是使用FastMCP了。

首先,需要安装依赖:

Plain 复制代码
uv add fastmcp

接着,只需要定义几个方法,然后利用FastMCP提供的装饰器即可:

  • @mcp.tool : 作为MCP中的工具
  • @mcp.resources : 返回MCP需要的resources,类似拓展知识库
  • @mcp.prompt : 返回MCP预定义的Prompt,预设的提示词

说明:MCP server端不仅可以提供tool,还可以提供resource、prompt,但通常不太常用,一般只需要提供tool即可。

通常我们只需要定义带有tool的MCP Server就可以了。

例如,我们定义一个数学运算的MCP服务,这个需要写到单独的py文件中,比如math_mcp_server.py:

Python 复制代码
from fastmcp import FastMCP

# 初始化mcp
mcp = FastMCP("Math")


# mcp tools
@mcp.tool()
def add(a: float, b: float) -> float:
    """Add two numbers"""
    return a + b


@mcp.tool()
def multiply(a: float, b: float) -> float:
    """Multiply two numbers"""
    return a * b


@mcp.tool
def square_root(x: float) -> float:
    """Calculate the square root of a number"""
    return x ** 0.5


# 启动mcp服务,通信方式设置为stdio
if __name__ == "__main__":
    mcp.run(transport="stdio")

一个自定义MCP server就准备好了。

注意,由于我们是采用stdio方式,因此这个文件写好放在那里,不需要启动,将来MCP Client会自己启动并加载为子进程。

3.2 连接接自定义MCP服务

由于我们自定义的MCP是本地py文件,所以启动的Command直接就是python,而不是npx或uvx

Python 复制代码
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain.agents import create_agent
from langchain_core.messages import HumanMessage

# 连接自定义MCP服务
client = MultiServerMCPClient(
    {
        "math": {
            "transport": "stdio",
            "command": "python",
            "args": ["math_mcp_server.py"] # 这里是脚本所在的路径,此处是相对路径
        }
    }
)
# 获取工具
tools = await client.get_tools()

# 创建agent
agent = create_agent(
    model="deepseek-chat",
    tools=tools,
    system_prompt="You are a helpful agent. You must use tools to answer math question."
)

# 调用测试
response = await agent.ainvoke({
    "messages": [HumanMessage("467和529的平方根之和是多少?")]
})

for message in response["messages"]:
    message.pretty_print()

结果:

Python 复制代码
================================ Human Message =================================

467和529的平方根之和是多少?
================================== Ai Message ==================================

我们先分别计算467和529的平方根,再求和。

首先计算529的平方根:
Tool Calls:
  square_root (call_00_j3L1qg1mxSJIBS9jdxll9134)
 Call ID: call_00_j3L1qg1mxSJIBS9jdxll9134
  Args:
    x: 529
================================= Tool Message =================================
Name: square_root

[{'type': 'text', 'text': '23.0', 'id': 'lc_423ebda4-fa3a-4d89-bb01-735ca14f9802'}]
================================== Ai Message ==================================

529的平方根是23。

接下来计算467的平方根:
Tool Calls:
  square_root (call_00_UCdL2SvqlmCaUESPUWNk9123)
 Call ID: call_00_UCdL2SvqlmCaUESPUWNk9123
  Args:
    x: 467
================================= Tool Message =================================
Name: square_root

[{'type': 'text', 'text': '21.61018278497431', 'id': 'lc_0878fcd8-c507-4323-bd74-332c0089e9a7'}]
================================== Ai Message ==================================

467的平方根约为21.61018278497431。

现在将两者相加:
Tool Calls:
  add (call_00_0dqFXu63t1T0iFZPtag58521)
 Call ID: call_00_0dqFXu63t1T0iFZPtag58521
  Args:
    a: 21.61018278497431
    b: 23
================================= Tool Message =================================
Name: add

[{'type': 'text', 'text': '44.61018278497431', 'id': 'lc_aed59d32-0c84-4f18-b704-96bf1c5c640c'}]
================================== Ai Message ==================================

467和529的平方根之和约为 **44.6102**。

具体计算步骤如下:
- √529 = 23
- √467 ≈ 21.61018278497431
- 两者相加 ≈ 44.61018278497431

四、总结

  1. MCP是什么
    • 开放协议,标准化LLM应用获取工具的方式
    • 客户端-服务器架构
  2. 连接方式
    • STDIO: 本地MCP服务器
    • HTTP: 远程MCP服务器
  3. 使用流程
    • 配置MultiServerMCPClient
    • 调用get_tools()获取工具
    • 创建Agent并调用
  4. 自定义MCP Server
    • 导入FastMCP
    • 使用@mcp.tool装饰函数,定义工具(必备)
    • 使用@mcp.resource装饰函数,返回resources(可选)
    • 使用@mcp.prompt装饰函数,返回Prompt(可选)
    • 使用mcp.run()启动MCP服务
相关推荐
爱编程的小新☆4 小时前
LangChain 智能体实战:构建技术学习规划 Agent
langchain·agent·工具调用·结构化输出·deepseek·流式输出
打工仔折腾 AI4 小时前
AI Agent 工程化实战(二):5 分钟跑通 Deep Agent 并逐层拆解底层链路
java·数据库·人工智能·后端·python·langchain·ai agent 实战
云和数据.ChenGuang4 小时前
Python map() 函数详解:从语法、原理到实战用法
开发语言·人工智能·python·langchain·1024程序员节
vjmap21 小时前
WebGIS + AI 智能体:唯杰地图智能体平台一句话处理 CAD 图纸,支持 MCP 接入 AI 编辑器
gis·agent·mcp
LMT流氓兔1 天前
第五单元——第十二课:把脚本整理成项目
java·数据库·python·langchain·1024程序员节
Maiko Star1 天前
*【HM-LC】 LangChain Runtime详解:Context、State与Store &飞书资料参考
langchain·runtime
slacker-kian1 天前
RAG 实战:用 LangChain + LLM 对私有文档做摘要提取
ai·langchain·llm·agent·rag
先吃饱再说1 天前
LangGraph 状态图:从节点、边到中断恢复,手写一个多 Agent 工作流
人工智能·langchain·llm
染指11101 天前
155.Agent-LangGraph-节点级重试策略
人工智能·langchain·1024程序员节·agents