课程:构建 Web 搜索 MCP 服务器
本章演示如何构建一个真实的 AI 代理,该代理能够集成外部 API、处理各种数据类型、管理错误并协调多种工具,并且所有功能均以生产就绪的形式实现。您将看到:
- 与需要身份验证的外部 API 集成
- 处理来自多个端点的不同数据类型
- 强大的错误处理和日志记录策略
- 单个服务器中的多工具编排
最后,您将拥有对于高级 AI 和 LLM 驱动的应用程序至关重要的模式和最佳实践的实践经验。
介绍
在本课中,你将学习如何构建高级 MCP 服务器和客户端,并使用 SerpAPI 扩展 LLM 功能,使其能够处理实时 Web 数据。这对于开发能够访问 Web 最新信息的动态 AI 代理至关重要。
学习目标
学完本课后,您将能够:
- 将外部 API(如 SerpAPI)安全地集成到 MCP 服务器中
- 为网络、新闻、产品搜索和问答实施多种工具
- 解析并格式化结构化数据以供 LLM 使用
- 处理错误并有效管理 API 速率限制
- 构建和测试自动化和交互式 MCP 客户端
网页搜索 MCP 服务器
本节介绍 Web Search MCP 服务器的架构和功能。您将了解如何结合使用 FastMCP 和 SerpAPI,利用实时 Web 数据扩展 LLM 功能。
概述
该实现包含四种工具,展示了 MCP 安全高效地处理各种外部 API 驱动任务的能力:
- general_search:用于广泛的网络搜索结果
- news_search:查找最近的头条新闻
- product_search:用于电子商务数据
- qna:用于问答片段
特征
- 代码示例:包括针对 Python 的特定语言代码块(并且可以轻松扩展到其他语言),使用可折叠部分以提高清晰度
# Example usage of the general_search tool
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def run_search():
server_params = StdioServerParameters(
command="python",
args=["server.py"],
)
async with stdio_client(server_params) as (reader, writer):
async with ClientSession(reader, writer) as session:
await session.initialize()
result = await session.call_tool("general_search", arguments={"query": "open source LLMs"})
print(result)
在运行客户端之前,了解服务器的功能会很有帮助。该server.py文件实现了 MCP 服务器,通过与 SerpAPI 集成,提供了用于网页、新闻、产品搜索和问答的工具。它负责处理传入的请求、管理 API 调用、解析响应并向客户端返回结构化结果。
您可以在中查看完整的实施情况server.py。
以下是服务器如何定义和注册工具的简单示例:
Python服务器# server.py (excerpt)
from mcp.server import MCPServer, Tool
async def general_search(query: str):
# ...implementation...
server = MCPServer()
server.add_tool(Tool("general_search", general_search))
if __name__ == "__main__":
server.run()
- 外部 API 集成:演示 API 密钥和外部请求的安全处理
- 结构化数据解析:展示如何将 API 响应转换为 LLM 友好的格式
- 错误处理:通过适当的日志记录实现强大的错误处理
- 交互式客户端:包括自动化测试和交互式测试模式
- 上下文管理:利用 MCP 上下文记录和跟踪请求
先决条件
开始之前,请按照以下步骤确保您的环境已正确设置。这将确保所有依赖项均已安装,并且 API 密钥已正确配置,以便无缝进行开发和测试。
- Python 3.8 或更高版本
- SerpAPI API 密钥(在SerpAPI注册- 提供免费套餐)
安装
首先,请按照以下步骤设置您的环境:
- 使用 uv(推荐)或 pip 安装依赖项:
# Using uv (recommended)
uv pip install -r requirements.txt
# Using pip
pip install -r requirements.txt
.env
使用您的 SerpAPI 密钥在项目根目录中创建一个文件:
<span style="background-color:#151b23"><span style="color:#f0f6fc"><span style="background-color:#151b23"><code>SERPAPI_KEY=your_serpapi_key_here
</code></span></span></span>
用法
Web 搜索 MCP 服务器是核心组件,它通过与 SerpAPI 集成,提供用于网页、新闻、产品搜索和问答的工具。它负责处理传入请求、管理 API 调用、解析响应并向客户端返回结构化结果。
您可以在中查看完整的实施情况server.py。
运行服务器
要启动 MCP 服务器,请使用以下命令:
python server.py
该服务器将作为基于 stdio 的 MCP 服务器运行,客户端可以直接连接。
客户端模式
客户端(client.py
)支持两种与 MCP 服务器交互的模式:
- 正常模式:运行自动化测试,测试所有工具并验证其响应。这有助于快速检查服务器和工具是否按预期运行。
- 交互模式:启动菜单驱动的界面,您可以在其中手动选择和调用工具、输入自定义查询并实时查看结果。这非常适合探索服务器的功能并尝试不同的输入。
您可以在中查看完整的实施情况client.py。
运行客户端
运行自动化测试(这将自动启动服务器):
python client.py
或者以交互模式运行:
python client.py --interactive
使用不同方法进行测试
根据您的需求和工作流程,有多种方法可以测试和与服务器提供的工具交互。
使用 MCP Python SDK 编写自定义测试脚本
您还可以使用 MCP Python SDK 构建自己的测试脚本:
Pythonfrom mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def test_custom_query():
server_params = StdioServerParameters(
command="python",
args=["server.py"],
)
async with stdio_client(server_params) as (reader, writer):
async with ClientSession(reader, writer) as session:
await session.initialize()
# Call tools with your custom parameters
result = await session.call_tool("general_search",
arguments={"query": "your custom query"})
# Process the result
在本文中,“测试脚本”是指您编写的自定义 Python 程序,用作 MCP 服务器的客户端。此脚本并非正式的单元测试,而是允许您以编程方式连接到服务器,使用您选择的参数调用服务器的任何工具,并检查结果。此方法适用于:
- 原型设计和实验工具调用
- 验证服务器如何响应不同的输入
- 自动重复调用工具
- 在 MCP 服务器上构建您自己的工作流程或集成
您可以使用测试脚本快速尝试新查询、调试工具行为,甚至可以将其作为更高级自动化的起点。以下是如何使用 MCP Python SDK 创建此类脚本的示例:
工具描述
您可以使用服务器提供的以下工具执行不同类型的搜索和查询。下面介绍了每个工具及其参数和使用示例。
本节提供有关每个可用工具及其参数的详细信息。
general_search
执行常规网络搜索并返回格式化的结果。
如何调用此工具:
您可以general_search
使用 MCP Python SDK 从您自己的脚本调用,也可以使用 Inspector 或交互式客户端模式进行交互。以下是使用 SDK 的代码示例:
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def run_general_search():
server_params = StdioServerParameters(
command="python",
args=["server.py"],
)
async with stdio_client(server_params) as (reader, writer):
async with ClientSession(reader, writer) as session:
await session.initialize()
result = await session.call_tool("general_search", arguments={"query": "latest AI trends"})
print(result)
或者,在交互模式下,general_search
从菜单中选择并在出现提示时输入您的查询。
参数:
query
(字符串):搜索查询
示例请求:
{
"query": "latest AI trends"
}
新闻搜索
搜索与查询相关的最新新闻文章。
如何调用此工具:
您可以news_search
使用 MCP Python SDK 从您自己的脚本调用,也可以使用 Inspector 或交互式客户端模式进行交互。以下是使用 SDK 的代码示例:
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def run_news_search():
server_params = StdioServerParameters(
command="python",
args=["server.py"],
)
async with stdio_client(server_params) as (reader, writer):
async with ClientSession(reader, writer) as session:
await session.initialize()
result = await session.call_tool("news_search", arguments={"query": "AI policy updates"})
print(result)
或者,在交互模式下,news_search
从菜单中选择并在出现提示时输入您的查询。
参数:
query
(字符串):搜索查询
示例请求:
{
"query": "AI policy updates"
}
产品搜索
搜索与查询匹配的产品。
如何调用此工具:
您可以product_search
使用 MCP Python SDK 从您自己的脚本调用,也可以使用 Inspector 或交互式客户端模式进行交互。以下是使用 SDK 的代码示例:
或者,在交互模式下,product_search
从菜单中选择并在出现提示时输入您的查询。
参数:
query
(字符串):产品搜索查询
示例请求:
{
"query": "best AI gadgets 2025"
}
问答
从搜索引擎直接获取问题的答案。
如何调用此工具:
您可以qna
使用 MCP Python SDK 从您自己的脚本调用,也可以使用 Inspector 或交互式客户端模式进行交互。以下是使用 SDK 的代码示例:
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
async def run_qna():
server_params = StdioServerParameters(
command="python",
args=["server.py"],
)
async with stdio_client(server_params) as (reader, writer):
async with ClientSession(reader, writer) as session:
await session.initialize()
result = await session.call_tool("qna", arguments={"question": "what is artificial intelligence"})
print(result)
或者,在交互模式下,qna
从菜单中选择并在出现提示时输入您的问题。
参数:
question
(字符串):需要寻找答案的问题
示例请求:
{
"question": "what is artificial intelligence"
}
代码详细信息
本节提供服务器和客户端实现的代码片段和参考。
Python请参阅server.py和client.py了解完整的实施细节。
# Example snippet from server.py:
import os
import httpx
# ...existing code...
本课中的高级概念
在开始构建之前,以下是一些贯穿本章的重要高级概念。理解这些概念将有助于您跟上本章的进度,即使您是新手:
- 多工具编排:这意味着在单个 MCP 服务器中运行多个不同的工具(例如网页搜索、新闻搜索、产品搜索和问答)。它使您的服务器能够处理多种任务,而不仅仅是单一任务。
- API 速率限制处理:许多外部 API(例如 SerpAPI)会限制您在特定时间内可以发出的请求数量。优秀的代码会检查这些限制并妥善处理,这样即使达到限制,您的应用也不会崩溃。
- 结构化数据解析:API 响应通常复杂且嵌套。此概念旨在将这些响应转换为简洁易用的格式,以便 LLM 或其他程序能够轻松处理。
- 错误恢复:有时事情会出错——比如网络故障,或者 API 没有返回预期结果。错误恢复意味着您的代码可以处理这些问题,并且仍然提供有用的反馈,而不会崩溃。
- 参数验证:这是为了检查工具的所有输入是否正确且可以安全使用。它包括设置默认值并确保类型正确,这有助于防止错误和混淆。
本部分将帮助您诊断和解决使用 Web 搜索 MCP 服务器时可能遇到的常见问题。如果您在使用 Web 搜索 MCP 服务器时遇到错误或异常行为,本故障排除部分提供了最常见问题的解决方案。在寻求进一步帮助之前,请先阅读这些提示——它们通常可以快速解决问题。
故障排除
使用网页搜索 MCP 服务器时,您偶尔可能会遇到问题——这在使用外部 API 和新工具进行开发时很正常。本部分提供了一些针对最常见问题的实用解决方案,以便您快速恢复正常。如果您遇到错误,请从此处开始:以下提示可解决大多数用户遇到的问题,并且通常无需额外帮助即可解决您的问题。
常见问题
以下是用户遇到的一些最常见的问题,以及清晰的解释和解决方法:
-
.env 文件中缺少 SERPAPI_KEY
- 如果您看到错误
SERPAPI_KEY environment variable not found
,则表示您的应用程序找不到访问 SerpAPI 所需的 API 密钥。要解决此问题,请.env
在项目根目录中创建一个名为 的文件(如果该文件尚不存在),并添加类似 的行SERPAPI_KEY=your_serpapi_key_here
。请确保将 替换your_serpapi_key_here
为您在 SerpAPI 网站上获取的实际密钥。
- 如果您看到错误
-
未找到模块错误
- 诸如 之类的错误
ModuleNotFoundError: No module named 'httpx'
表明缺少所需的 Python 包。这通常是由于您尚未安装所有依赖项而发生的。要解决此问题,请pip install -r requirements.txt
在终端中运行以安装项目所需的所有内容。
- 诸如 之类的错误
-
连接问题
- 如果您收到类似 的错误
Error during client execution
,通常表示客户端无法连接到服务器,或者服务器未按预期运行。请仔细检查客户端和服务器的版本是否兼容,以及它们server.py
是否已存在并运行在正确的目录中。重新启动服务器和客户端也可能有帮助。
- 如果您收到类似 的错误
-
SerpAPI 错误
- 看到此信息
Search API returned error status: 401
表示您的 SerpAPI 密钥缺失、不正确或已过期。请前往您的 SerpAPI 信息中心,验证您的密钥,并.env
根据需要更新文件。如果您的密钥正确,但仍然看到此错误,请检查您的免费套餐是否已用完配额。
- 看到此信息
调试模式
默认情况下,该应用仅记录重要信息。如果您想查看更多详细信息(例如,诊断棘手问题),可以启用“调试”模式。这将向您显示应用执行的每个步骤的详细信息。
示例:正常输出
<span style="background-color:#151b23"><span style="color:#f0f6fc"><span style="background-color:#151b23"><code>2025-06-01 10:15:23,456 - __main__ - INFO - Calling general_search with params: {'query': 'open source LLMs'}
2025-06-01 10:15:24,123 - __main__ - INFO - Successfully called general_search
GENERAL_SEARCH RESULTS:
... (search results here) ...
</code></span></span></span>
示例:DEBUG 输出
<span style="background-color:#151b23"><span style="color:#f0f6fc"><span style="background-color:#151b23"><code>2025-06-01 10:15:23,456 - __main__ - INFO - Calling general_search with params: {'query': 'open source LLMs'}
2025-06-01 10:15:23,457 - httpx - DEBUG - HTTP Request: GET https://serpapi.com/search ...
2025-06-01 10:15:23,458 - httpx - DEBUG - HTTP Response: 200 OK ...
2025-06-01 10:15:24,123 - __main__ - INFO - Successfully called general_search
GENERAL_SEARCH RESULTS:
... (search results here) ...
</code></span></span></span>
请注意,DEBUG 模式包含有关 HTTP 请求、响应和其他内部详细信息的额外行。这对于故障排除非常有帮助。
client.py
要启用 DEBUG 模式,请在或顶部将日志记录级别设置为 DEBUG server.py
:
# At the top of your client.py or server.py
import logging
logging.basicConfig(
level=logging.DEBUG, # Change from INFO to DEBUG
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)