🔌 OpenClaw 自定义MCP服务器开发

给OpenClaw装上"任意门"——让Agent能调用任何你想要的私有工具

什么是MCP?为什么需要自定义?

世界上有一种协议叫MCP(Model Context Protocol),它就像AI世界的"USB接口"——任何支持MCP的工具,都能插进OpenClaw。

但问题来了:你的公司内部API、私有数据库、自研工具,它们可不支持MCP。这时候,你需要自己写一个MCP Server,把它们"翻译"成OpenClaw能懂的语言。

🎯 自定义MCP Server的五大场景:
  • 私有数据库:让Agent直接查询公司内部MySQL/PostgreSQL
  • 内部API:对接公司ERP、CRM、OA系统
  • 自研工具:把你们团队的工具变成Agent可调用的能力
  • 硬件设备:让Agent控制IoT设备、机器人、传感器
  • 特殊数据源:调用付费API、内网服务、加密数据源

MCP Server 核心概念

MCP Server需要实现三个核心方法:

① tools/list - 告诉Agent"我有哪些工具可用"
② tools/call - 执行Agent指定的工具调用
③ resources/list - (可选)提供可读取的数据资源

实战:构建一个"公司HR系统"MCP Server

假设你的公司有一个HR系统API,你想让Agent能查询员工信息、请假记录等。

第一步:设计工具清单

// hr-mcp-server/tools-definition.json
{
  "tools": [
    {
      "name": "get_employee_info",
      "description": "查询员工基本信息(姓名、部门、职级)",
      "inputSchema": {
        "type": "object",
        "properties": {
          "employee_id": {
            "type": "string",
            "description": "员工ID,格式:EMP + 6位数字"
          }
        },
        "required": ["employee_id"]
      }
    },
    {
      "name": "list_leave_requests",
      "description": "查询员工的请假记录",
      "inputSchema": {
        "type": "object",
        "properties": {
          "employee_id": {"type": "string"},
          "start_date": {"type": "string", "format": "date"},
          "end_date": {"type": "string", "format": "date"}
        },
        "required": ["employee_id"]
      }
    },
    {
      "name": "submit_leave_request",
      "description": "提交新的请假申请",
      "inputSchema": {
        "type": "object",
        "properties": {
          "employee_id": {"type": "string"},
          "leave_type": {"type": "string", "enum": ["年假", "病假", "事假", "婚假"]},
          "start_date": {"type": "string"},
          "end_date": {"type": "string"},
          "reason": {"type": "string"}
        },
        "required": ["employee_id", "leave_type", "start_date", "end_date"]
      }
    }
  ]
}

第二步:实现MCP Server(Python版)

# hr-mcp-server/server.py
import json
import asyncio
from typing import Any
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent

# 模拟HR系统API(实际项目中替换为真实API调用)
HR_SYSTEM_API = "https://hr.internal.company.com/api"

server = Server("company-hr-mcp-server")

@server.list_tools()
async def list_tools() -> list[Tool]:
    """告诉Agent有哪些工具可用"""
    return [
        Tool(
            name="get_employee_info",
            description="查询员工基本信息(姓名、部门、职级)",
            inputSchema={
                "type": "object",
                "properties": {
                    "employee_id": {"type": "string", "description": "员工ID"}
                },
                "required": ["employee_id"]
            }
        ),
        Tool(
            name="list_leave_requests",
            description="查询员工的请假记录",
            inputSchema={
                "type": "object",
                "properties": {
                    "employee_id": {"type": "string"},
                    "start_date": {"type": "string", "format": "date"},
                    "end_date": {"type": "string", "format": "date"}
                },
                "required": ["employee_id"]
            }
        ),
        Tool(
            name="submit_leave_request",
            description="提交新的请假申请",
            inputSchema={
                "type": "object",
                "properties": {
                    "employee_id": {"type": "string"},
                    "leave_type": {"type": "string", "enum": ["年假", "病假", "事假", "婚假"]},
                    "start_date": {"type": "string"},
                    "end_date": {"type": "string"},
                    "reason": {"type": "string"}
                },
                "required": ["employee_id", "leave_type", "start_date", "end_date"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: Any) -> list[TextContent]:
    """执行工具调用"""
    if name == "get_employee_info":
        emp_id = arguments.get("employee_id")
        # 实际项目中:调用HR系统API
        # response = requests.get(f"{HR_SYSTEM_API}/employees/{emp_id}", headers=auth_headers)
        mock_data = {
            "employee_id": emp_id,
            "name": "张三",
            "department": "技术部",
            "level": "P7",
            "join_date": "2020-03-15"
        }
        return [TextContent(type="text", text=json.dumps(mock_data, ensure_ascii=False))]

    elif name == "list_leave_requests":
        emp_id = arguments.get("employee_id")
        mock_leaves = [
            {"date": "2026-05-01", "type": "年假", "days": 3, "status": "已批准"},
            {"date": "2026-04-15", "type": "病假", "days": 1, "status": "已批准"}
        ]
        return [TextContent(type="text", text=json.dumps(mock_leaves, ensure_ascii=False))]

    elif name == "submit_leave_request":
        # 实际项目中:POST到HR系统API
        result = {"status": "success", "request_id": "LR-2026-0521-001"}
        return [TextContent(type="text", text=json.dumps(result, ensure_ascii=False))]

    return [TextContent(type="text", text="未知工具")]

async def main():
    async with stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            server.create_initialization_options()
        )

if __name__ == "__main__":
    asyncio.run(main())

第三步:配置到OpenClaw

# ~/.openclaw/config.yaml 中添加MCP服务器配置
mcpServers:
  company-hr:
    command: "python"
    args:
      - "/path/to/hr-mcp-server/server.py"
    env:
      HR_API_KEY: "${HR_API_KEY}"  # 从环境变量读取
    # 可选:添加描述,帮助Agent理解何时使用
    description: "公司HR系统工具,可以查询员工信息、请假记录、提交请假申请"

# 重启OpenClaw使配置生效
openclaw gateway restart

第四步:在OpenClaw中使用

# Agent现在可以调用你的HR工具了
openclaw chat --message "查询员工EMP123456的基本信息,然后看看他最近有没有请假"

# Agent会自动:
# 1. 调用 get_employee_info(employee_id="EMP123456")
# 2. 调用 list_leave_requests(employee_id="EMP123456")
# 3. 整合结果,生成回答

# 你也可以直接在提示中指定
openclaw chat --message "帮我提交一个请假申请" \
  --tool company-hr/submit_leave_request \
  --args '{"employee_id": "EMP123456", "leave_type": "年假", "start_date": "2026-06-01", "end_date": "2026-06-03", "reason": "家庭旅行"}'

进阶:添加认证和安全

⚠️ 安全提示:

MCP Server直接对接内部系统,必须做好安全防护!

# hr-mcp-server/auth.py - 添加认证中间件
import os
from functools import wraps

def require_auth(func):
    @wraps(func)
    async def wrapper(*args, **kwargs):
        # 从环境变量读取API Key
        expected_key = os.getenv("HR_MCP_API_KEY")
        provided_key = kwargs.get("context", {}).get("api_key")
        
        if not expected_key or provided_key != expected_key:
            return [TextContent(type="text", text="认证失败:无效的API Key")]
        
        return await func(*args, **kwargs)
    return wrapper

# 在call_tool中使用
@server.call_tool()
@require_auth
async def call_tool(name: str, arguments: Any):
    # ... 原有逻辑
    pass

常见MCP Server模板

Server类型 适用场景 核心工具
数据库MCP 查询MySQL/PostgreSQL query, insert, update, schema_info
API代理MCP 包装第三方API get, post, put, delete
文件系统MCP 读写服务器文件 read_file, write_file, list_dir
IoT设备MCP 控制智能设备 get_status, set_config, send_command
消息推送MCP 发送通知/邮件 send_email, send_sms, push_wechat

调试技巧

  1. stdio模式测试:直接用 echo '{"jsonrpc":"2.0","method":"tools/list"}' | python server.py 测试
  2. 日志输出:在Server中加 print(json.dumps(log_entry), file=sys.stderr),OpenClaw会捕获stderr
  3. OpenClaw日志tail -f ~/.openclaw/logs/mcp-company-hr.log 查看调用记录
  4. 工具测试openclaw mcp test company-hr get_employee_info --args '{"employee_id":"EMP001"}'
🎯 妙趣提示:

写MCP Server就像给Agent当翻译——把"人类系统的语言"翻译成"AI能懂的语言"。翻译得越准确,Agent干活越利索。

性能优化

生成时间:2026-05-21 01:00 (Asia/Shanghai) | 妙趣AI - AI营销运营官