SDK 自带的工具(Bash、Read、Write 等)能做很多事,但有时候你需要更专业的工具:

第 4 课:自定义工具——MCP Server


为什么需要自定义工具?

SDK 自带的工具(Bash、Read、Write 等)能做很多事,但有时候你需要更专业的工具:

bash
内置工具能做的:
  ✅ 执行 shell 命令
  ✅ 读写文件

你需要的:
  ❌ 调用公司内部 API
  ❌ 查询数据库
  ❌ 操作 Docker 容器
  ❌ 读取 Kubernetes Pod 状态
  ❌ 发送告警通知

MCP(Model Context Protocol)Server 就是用来解决这个问题的——把任何 Python 函数变成 AI 可以调用的工具

@tool 装饰器

最核心的就是 @tool 装饰器。它把一个普通的 Python 函数变成 AI 的工具:

code
from claude_agent_sdk import tool

@tool("工具名", "工具描述", {"参数名": 参数类型})
async def 你的函数(args):
    # 你的逻辑
    return {"content": [{"type": "text", "text": "返回结果"}]}

实战:创建 Git 工具

code
from claude_agent_sdk import tool
import subprocess

@tool("git_status", "查看 Git 仓库状态", {})
async def git_status(args):
    """查看当前仓库的 git status"""
    result = subprocess.run(
        ["git", "status", "--porcelain"],
        capture_output=True, text=True
    )
    output = result.stdout if result.stdout else "工作区是干净的"
    return {"content": [{"type": "text", "text": output}]}


@tool("git_log", "查看最近的提交记录", {"count": int})
async def git_log(args):
    """查看最近 N 条提交记录"""
    count = args.get("count", 5)
    result = subprocess.run(
        ["git", "log", f"--oneline", f"-{count}"],
        capture_output=True, text=True
    )
    return {"content": [{"type": "text", "text": result.stdout}]}


@tool("git_diff", "查看文件改动", {"file": str})
async def git_diff(args):
    """查看指定文件的 diff"""
    file_path = args.get("file", "")
    cmd = ["git", "diff", file_path] if file_path else ["git", "diff"]
    result = subprocess.run(cmd, capture_output=True, text=True)
    return {"content": [{"type": "text", "text": result.stdout or "没有改动"}]}

注册到 MCP Server

写好工具函数后,用 create_sdk_mcp_server() 把它们打包成一个服务器:

code
from claude_agent_sdk import create_sdk_mcp_server

# 把工具打包成一个 MCP 服务器
git_server = create_sdk_mcp_server(
    name="git-tools",
    version="1.0.0",
    tools=[git_status, git_log, git_diff],
)

在 query() 或 Client 中使用

code
from claude_agent_sdk import query, ClaudeAgentOptions

options = ClaudeAgentOptions(
    mcp_servers={"git": git_server},  # 注册 MCP 服务器
    allowed_tools=[
        "mcp__git__git_status",   # 格式:mcp__服务器名__工具名
        "mcp__git__git_log",
        "mcp__git__git_diff",
    ],
    system_prompt="你是 Git 助手,帮用户管理代码仓库。",
)

async for msg in query(
    prompt="看看仓库状态,最近 3 条提交,以及有什么改动",
    options=options,
):
    # 处理消息...
    pass

AI 现在可以像调用内置工具一样调用你的自定义工具了!

工具命名规则

自定义工具在 allowed_tools 里的名字格式是:

code
mcp__<服务器名>__<工具名>

例子:
  mcp__git__git_status
  mcp__git__git_log
  mcp__docker__list_containers

更多 DevOps 工具示例

Docker 工具

code
@tool("list_containers", "列出 Docker 容器", {"all": bool})
async def list_containers(args):
    show_all = args.get("all", False)
    cmd = ["docker", "ps"]
    if show_all:
        cmd.append("-a")
    result = subprocess.run(cmd, capture_output=True, text=True)
    return {"content": [{"type": "text", "text": result.stdout}]}


@tool("container_logs", "查看容器日志", {"container": str, "lines": int})
async def container_logs(args):
    container = args["container"]
    lines = args.get("lines", 50)
    result = subprocess.run(
        ["docker", "logs", "--tail", str(lines), container],
        capture_output=True, text=True
    )
    output = result.stdout + result.stderr
    return {"content": [{"type": "text", "text": output}]}

健康检查工具

code
import urllib.request
import json

@tool("health_check", "检查服务健康状态", {"url": str})
async def health_check(args):
    url = args["url"]
    try:
        req = urllib.request.urlopen(url, timeout=5)
        status = req.getcode()
        return {"content": [{"type": "text",
            "text": f"✅ {url} → HTTP {status}"}]}
    except Exception as e:
        return {"content": [{"type": "text",
            "text": f"❌ {url} → 失败: {str(e)}"}],
            "is_error": True}

告警通知工具

code
@tool("send_alert", "发送告警通知", {"message": str, "level": str})
async def send_alert(args):
    message = args["message"]
    level = args.get("level", "info")

    # 这里可以接入你的告警系统:飞书、钉钉、Slack 等
    print(f"[{level.upper()}] 告警: {message}")

    return {"content": [{"type": "text",
        "text": f"告警已发送: [{level}] {message}"}]}

工具中访问应用状态

MCP 工具的一个强大之处:工具函数可以直接访问你的 Python 应用状态

code
# 应用级别的状态
deployment_history = []

@tool("record_deployment", "记录部署", {"version": str, "env": str})
async def record_deployment(args):
    # 直接访问应用状态!
    deployment_history.append({
        "version": args["version"],
        "env": args["env"],
        "time": datetime.now().isoformat(),
    })
    return {"content": [{"type": "text",
        "text": f"已记录部署: {args['version']}{args['env']}"}]}

@tool("list_deployments", "查看部署历史", {})
async def list_deployments(args):
    if not deployment_history:
        return {"content": [{"type": "text", "text": "没有部署记录"}]}
    history = "\n".join(
        f"  {d['version']}{d['env']} @ {d['time']}"
        for d in deployment_history
    )
    return {"content": [{"type": "text", "text": history}]}

这比外部 MCP 服务器方便得多——不用 HTTP 通信、不用序列化,直接共享 Python 内存。

本课小结

  • @tool 装饰器把 Python 函数变成 AI 的工具
  • create_sdk_mcp_server() 把工具打包成 MCP 服务器
  • 工具命名格式:mcp__<服务器名>__<工具名>
  • 工具函数可以直接访问应用状态
  • 可以包装任何 API:Git、Docker、数据库、告警系统

课后练习

  1. 把上面的 Git 工具跑起来,让 AI 帮你查看仓库状态
  2. 写一个 disk_usage 工具,让 AI 能查看磁盘使用情况
  3. 把多个工具合到一个 MCP Server 里,让 AI 同时使用

沿着当前专题继续,或返回课程目录重新整理阅读顺序。

返回课程目录