在开始编码之前,我们需要准备好开发环境。推荐使用虚拟环境来管理项目依赖,以避免库版本冲突。
1. 创建项目目录和虚拟环境
mkdir mcp_project
cd mcp_project
python -m venv venv
source venv/bin/activate # 在 Windows 上使用 `venv\Scripts\activate`
2026/2/9...小于 1 分钟
在开始编码之前,我们需要准备好开发环境。推荐使用虚拟环境来管理项目依赖,以避免库版本冲突。
mkdir mcp_project
cd mcp_project
python -m venv venv
source venv/bin/activate # 在 Windows 上使用 `venv\Scripts\activate`
现在,我们将创建服务器的核心逻辑。fastapi-mcp 库的核心思想是,它可以自动将您的 FastAPI 路由(endpoints)转换为 AI 模型可以理解的 MCP 工具和资源。
在您的项目目录 (mcp_project) 中,创建一个名为 server.py 的文件。
将以下代码粘贴到 server.py 文件中。
import os
import httpx
from fastapi import FastAPI, HTTPException
from fastapi_mcp import FastApiMCP
# 1. 创建一个 FastAPI 应用实例
app = FastAPI(
title="我的第一个MCP服务器",
description="一个包含网络搜索工具和文件读取资源的MCP服务器。",
version="1.0.0",
)
# 2. 实现网络搜索“工具”
@app.post("/search", summary="执行网络搜索")
async def web_search(query: str):
"""
使用DuckDuckGo API执行网络搜索并返回结果。
"""
print(f"正在执行网络搜索: {query}")
try:
async with httpx.AsyncClient() as client:
response = await client.get(f"https://api.duckduckgo.com/?q={query}&format=json")
response.raise_for_status()
data = response.json()
if data.get("AbstractText"):
return {"result": data["AbstractText"]}
elif data.get("RelatedTopics"):
return {"result": [topic.get("Text") for topic in data["RelatedTopics"][:5]]}
else:
return {"result": "未找到相关信息。"}
except httpx.RequestError as exc:
raise HTTPException(status_code=500, detail=f"网络请求错误: {exc}")
# 3. 实现文件读取“资源”
@app.get("/read_file", summary="读取本地文件的内容")
async def read_local_file(file_path: str):
"""
根据提供的路径读取本地文件的内容。
"""
base_dir = os.path.abspath(os.path.dirname(__file__))
full_path = os.path.abspath(os.path.join(base_dir, file_path))
if not full_path.startswith(base_dir):
raise HTTPException(status_code=403, detail="禁止访问指定路径的文件。")
try:
with open(full_path, 'r', encoding='utf-8') as f:
content = f.read()
return {"file_content": content}
except FileNotFoundError:
raise HTTPException(status_code=404, detail="文件未找到。")
except Exception as e:
raise HTTPException(status_code=500, detail=f"读取文件时发生错误: {e}")
# 4. 将 FastAPI 应用转换为 MCP 服务器
mcp = FastApiMCP(
app,
name="MyFirstMCPServer",
description="一个简单的MCP服务器,提供网络搜索和文件读取功能。",
base_url="http://localhost:8000",
)
mcp.mount()
if __name__ == "__main__":
import uvicorn
# 创建一个测试文件
with open("test.txt", "w", encoding="utf-8") as f:
f.write("这是用于测试MCP服务器文件读取功能的本地文件。")
uvicorn.run(app, host="127.0.0.1", port=8000)
最后,我们将创建一个简单的客户端来模拟 AI 模型(或 IDE)如何与 MCP 服务器交互。
创建一个名为 client.py 的文件。
import asyncio
import httpx
import json
SERVER_URL = "http://127.0.0.1:8000"
MCP_ENDPOINT = f"{SERVER_URL}/mcp"
async def main():
async with httpx.AsyncClient() as client:
print("--- 1. 初始化与MCP服务器的会话 ---")
init_response = await client.post(
MCP_ENDPOINT,
json={"jsonrpc": "2.0", "method": "initialize", "params": {"clientVersion": "0.1"}, "id": 1}
)
print("✅ 初始化成功!")
print("\n--- 2. 列出服务器上所有可用的工具和资源 ---")
list_tools_response = await client.post(
MCP_ENDPOINT,
json={"jsonrpc": "2.0", "method": "listTools", "params": {}, "id": 2}
)
tools = list_tools_response.json()["result"]["tools"]
for tool in tools:
print(f" - 工具/资源名称: {tool['name']}")
print("\n--- 3. 调用'web_search'工具 ---")
search_query = "FastAPI"
call_tool_response = await client.post(
MCP_ENDPOINT,
json={
"jsonrpc": "2.0",
"method": "callTool",
"params": {"name": "web_search", "arguments": {"query": search_query}},
"id": 3
}
)
# 注意:实际返回结构可能因实现而异,这里假设标准返回结构
print(f"🔍 搜索结果: {call_tool_response.json()['result']['content']['text']}")
if __name__ == "__main__":
asyncio.run(main())