1. Hello World:开发第一个Echo工具
1.1 基础代码解析
from mcp.server.fastmcp import FastMCP
# Create an MCP server instance with a custom name.
# 创建MCP服务器实例
mcp = FastMCP("EchoDemo")
# 注册工具
@mcp.tool()
def echo(text: str) -> str:
"""回显输入文本 | text: 需要回显的文本"""
return text
# 启动服务器
mcp.run()
1.2 关键点说明
MCPServer初始化参数是服务器名称,会显示在客户端@mcp.tool()装饰器将普通函数转换为MCP工具- 函数docstring中的
|分隔工具描述和参数说明
1.3 测试方法
- 保存为
echo_server.py - 启动服务器:
python echo_server.py - 在客户端(如Cursor)输入:
@echo 你好MCP - 应收到回复:
你好MCP
2. 数据库查询工具实战
2.1 连接SQLite数据库
import sqlite3
from typing import List, Dict
@mcp.tool()
def query_users(limit: int = 100) -> List[Dict]:
"""查询用户列表 | limit: 返回结果最大数量"""
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
try:
cursor.execute("SELECT * FROM users LIMIT ?", (limit,))
columns = [desc[0] for desc in cursor.description]
return [dict(zip(columns, row)) for row in cursor.fetchall()]
finally:
conn.close()
2.2 最佳实践
- 自动LIMIT处理:默认限制返回数量,防止大数据量
- 标准化返回:将结果转为字典列表,便于JSON序列化
- 错误处理:使用try-finally确保连接关闭
2.3 高级版本(带过滤条件)
@mcp.tool()
def query_users_by_age(min_age: int = 0, max_age: int = 100, limit: int = 100):
"""按年龄筛选用户 | min_age: 最小年龄 | max_age: 最大年龄 | limit: 返回数量"""
# 实现代码类似上面,SQL增加WHERE条件
3. 进阶功能开发
3.1 动态资源注册
@mcp.resource("greeting://{name}")
def generate_greeting(name: str):
"""动态生成问候语"""
return f"Hello, {name}!"
客户端调用方式:
@resource greeting://John
3.2 异步工具开发
import asyncio
@mcp.tool()
async def long_running_task():
"""长时间运行的任务"""
await asyncio.sleep(10)
return "任务完成"
3.3 带进度反馈的异步任务
@mcp.tool()
async def process_data(data: str):
"""处理数据并反馈进度"""
for i in range(1, 6):
await asyncio.sleep(1)
mcp.notify_progress(i/5, f"处理中... {i*20}%")
return "处理完成"
4. 完整示例:用户统计服务
import sqlite3
from typing import List, Dict
from mcp.server.fastmcp import FastMCP
# 创建MCP服务器实例
mcp = FastMCP("UserStats")
@mcp.tool()
def user_age_stats() -> Dict[str, int]:
"""统计用户年龄分布"""
conn = sqlite3.connect('users.db')
try:
cursor = conn.cursor()
cursor.execute("""
SELECT
CASE
WHEN age < 20 THEN 'Under 20'
WHEN age BETWEEN 20 AND 29 THEN '20s'
WHEN age BETWEEN 30 AND 39 THEN '30s'
ELSE '40+'
END as age_group,
COUNT(*) as count
FROM users
GROUP BY age_group
""")
return dict(cursor.fetchall())
finally:
conn.close()
if __name__ == "__main__":
mcp.run()
5. 调试技巧
- 使用MCP Inspector监控工具调用
- 打印调试日志:
@mcp.tool()
def debug_tool():
print("调试信息") # 会在服务器控制台显示
return "OK"
附录:常见错误处理
| 错误类型 | 解决方案 |
|---|---|
| 工具未注册 | 检查是否添加了@mcp.tool()装饰器 |
| 参数解析失败 | 确保docstring中有参数说明 |
| 数据库连接泄漏 | 使用try-finally确保连接关闭 |
| 异步任务卡死 | 设置超时机制 |