MCP协议实战:从零搭建一个AI Agent工具服务器,让大模型真正“动手干活“

MCP协议实战:从零搭建一个AI Agent工具服务器,让大模型真正"动手干活"

说白了,大模型再聪明,不能调API、不能读数据库、不能操作文件,那就是个"嘴强王者"。MCP就是解决这个问题的。

前言

最近跟几个做AI应用的朋友聊天,发现大家都有同一个痛点:大模型能力确实强,但一到"动手"就歇菜。你让GPT帮你查个数据库?它只能给你写SQL,执行还得你自己来。你让它帮你发个邮件?它只能给你草稿,发送还得你自己点。

说真的,这个问题困扰了我挺久。直到我开始用MCP(Model Context Protocol),才感觉事情开始变得不一样了。

今天这篇文章,我就从零开始,手把手带你搭一个MCP工具服务器,让大模型真正能"动手干活"。不是那种hello world级别的demo,是一个能实际用起来的工具。

什么是MCP?30秒搞懂

MCP,全称 Model Context Protocol,是Anthropic在2024年底开源的一个协议。你可以把它理解成大模型的USB接口

以前你想让大模型连数据库,得写一套代码;想让它操作文件,又得写一套;想让它调API,再写一套。每个大模型(GPT、Claude、Gemini)的接入方式还不一样。

MCP统一了这个事儿。你只需要按照MCP协议写一个"工具服务器",所有支持MCP的大模型都能直接用。

架构很简单:

```

用户 → 大模型(MCP客户端)→ MCP协议 → 工具服务器 → 实际操作

```

大模型决定"要不要用工具、用哪个工具",工具服务器负责"怎么执行"。各司其职,干净利落。

环境准备

我用Python来写,因为生态最成熟。需要的东西:

  • Python 3.10+
  • mcp SDK(官方Python包)
  • 一个支持MCP的客户端(我用Claude Desktop,你用Cursor也行)

先装依赖:

```bash

pip install mcp httpx

```

就这么简单,没有一堆乱七八糟的依赖。

实战:搭建一个"系统信息查询"工具

我做了一个实用的MCP工具服务器,功能包括:

  1. 查询系统信息 --- CPU、内存、磁盘使用率
  2. 执行Shell命令 --- 安全沙箱内的命令执行
  3. 读取文件内容 --- 让大模型能直接读配置文件、日志

不是玩具,是真的能用的东西。

第一步:定义工具服务器骨架

```python

import asyncio

import json

import platform

import subprocess

import os

from mcp.server import Server

from mcp.server.stdio import stdio_server

from mcp.types import Tool, TextContent

server = Server("system-tools")

@server.list_tools()

async def list_tools():

"""告诉大模型:我有哪些工具可以用"""

return [

Tool(

name="get_system_info",

description="获取当前系统的CPU、内存、磁盘使用情况",

inputSchema={"type": "object", "properties": {}, "required": []}

),

Tool(

name="run_command",

description="在安全沙箱内执行Shell命令,返回输出结果",

inputSchema={

"type": "object",

"properties": {

"command": {"type": "string", "description": "要执行的Shell命令"}

},

"required": ["command"]

}

),

Tool(

name="read_file",

description="读取指定路径的文件内容",

inputSchema={

"type": "object",

"properties": {

"path": {"type": "string", "description": "文件的绝对路径"}

},

"required": ["path"]

}

)

]

```

注意看 list_tools() 这个函数,它的作用就是告诉大模型"我有什么能力"。description 很重要,大模型靠这个来判断什么时候该调用你的工具。

第二步:实现工具逻辑

```python

@server.call_tool()

async def call_tool(name: str, arguments: dict):

if name == "get_system_info":

import psutil

cpu_percent = psutil.cpu_percent(interval=1)

memory = psutil.virtual_memory()

disk = psutil.disk_usage('/')

info = {

"系统": platform.system(),

"CPU使用率": f"{cpu_percent}%",

"内存": f"{memory.used / (10243):.1f}GB / {memory.total / (1024 3):.1f}GB ({memory.percent}%)",

"磁盘": f"{disk.used / (10243):.1f}GB / {disk.total / (1024 3):.1f}GB ({disk.percent}%)"

}

return [TextContent(type="text", text=json.dumps(info, ensure_ascii=False, indent=2))]

复制代码
elif name == "run_command":
    cmd = arguments.get("command", "")
    dangerous = ["rm -rf", "mkfs", "dd if=", "> /dev/", "chmod 777"]
    if any(d in cmd for d in dangerous):
        return [TextContent(type="text", text="❌ 命令被安全策略拦截")]
    try:
        result = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=10)
        output = result.stdout if result.returncode == 0 else f"错误: {result.stderr}"
        return [TextContent(type="text", text=output[:2000])]
    except subprocess.TimeoutExpired:
        return [TextContent(type="text", text="❌ 命令执行超时(10秒限制)")]

elif name == "read_file":
    path = arguments.get("path", "")
    if not os.path.exists(path):
        return [TextContent(type="text", text=f"❌ 文件不存在: {path}")]
    try:
        with open(path, 'r', encoding='utf-8') as f:
            content = f.read(50000)
        return [TextContent(type="text", text=content)]
    except Exception as e:
        return [TextContent(type="text", text=f"❌ 读取失败: {str(e)}")]

```

重点说一下安全设计。run_command 这个工具能力很强,但也很危险。所以我加了两层保护:

  1. 黑名单过滤 --- 拦截 rm -rfmkfs 这类毁灭性命令
  2. 超时限制 --- 最多跑10秒,防止死循环

第三步:启动服务器

```python

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())

```

整个服务器就这些代码,不到100行。

第四步:配置客户端

以Claude Desktop为例,编辑配置文件:

```json

{

"mcpServers": {

"system-tools": {

"command": "python",

"args": ["/path/to/mcp_server.py"]

}

}

}

```

重启Claude Desktop,你就能在对话里直接让它查系统信息、执行命令、读文件了。

踩坑记录

搞MCP开发这段时间,踩过几个坑:

坑1:description写得不好,大模型不调用工具

description 是大模型决定"用不用这个工具"的唯一依据。写得太模糊,它就不用。写得太长,它也容易忽略。建议一句话说清楚"这个工具干什么"。

坑2:inputSchema校验太严格

大模型传参有时候会多传字段、少传字段、类型不对。你的Schema别定义得太死,required 只放真正必须的参数。

坑3:返回内容太长

大模型的上下文窗口有限。你的工具返回结果最好控制在合理长度内。我在 read_file 里限制了50KB,run_command 限制了2000字符。

坑4:Windows和Linux的命令差异

如果你的工具服务器要跨平台用,注意Shell命令的差异。比如 ls 在Windows上是 dirgrep 在Windows上是 findstr

进阶玩法

基础搞定了,你可以继续扩展:

  1. 接数据库 --- 写一个 query_sql 工具,让大模型直接查数据库
  2. 接API --- 封装你常用的API(天气、翻译、搜索)为MCP工具
  3. 接文件系统 --- 让大模型能读写项目文件,变成一个真正的"AI助手"
  4. 多工具协作 --- 一个服务器提供多个相关工具,让大模型自己编排工作流

我个人觉得最有价值的方向是把你的日常运维操作封装成MCP工具。比如查日志、重启服务、清理磁盘、检查告警。以后出了问题,你直接跟大模型说"帮我看看线上什么情况",它自己去查、自己分析、给你结论。

写在最后

MCP这个协议,说大不大,说小不小。它不是什么颠覆性技术,但它解决了一个实际问题:让大模型从"只会说"变成"能做事"

目前MCP生态还在早期,但增长很快。Claude、Cursor、Windsurf这些主流客户端都已经支持了。OpenAI据说也在跟进。

如果你现在就开始把你的工具封装成MCP服务器,等生态成熟的时候,你就已经领先一步了。


相关资源:


💬 你们在做大模型应用的时候,有没有遇到"大模型不能动手"的问题?欢迎评论区聊聊你的解决方案。

相关推荐
历程里程碑1 小时前
54 深入解析poll多路复用技术
java·linux·服务器·开发语言·前端·数据结构·c++
嗷嗷哦润橘_1 小时前
whynotTV徐丹飞:离通用智能机器人还有多远
人工智能·ai·具身智能
qq_543447821 小时前
Tcping测速是什么?Tcping测速核心概念解析
服务器·网络·php
手写码匠1 小时前
手写 AI 推理加速引擎:从零实现 KV Cache 与 Speculative Decoding
人工智能·深度学习·算法·aigc
Agent手记1 小时前
能源供应链智能体落地实战:从招标审核到备件调度,AI Agent全链路方案解析
人工智能·能源
不开大的凯20771 小时前
海外AI圈的“五月风暴”:一场没有硝烟的全面战争
大数据·人工智能
染指11101 小时前
7.相似度计算(本地模型下载和使用,在线模型的使用)-RAG基础1
人工智能·机器学习·阿里云·向量·rag
名不经传的养虾人1 小时前
从0到1:企业级AI项目迭代日记 Vol.28|企业AI的交付不是给工具,而是给搭好的能力
大数据·人工智能·ai编程·ai工作流·企业ai·多agent协作
上海云盾-小余1 小时前
验证码接口攻防实战:杜绝拖拽刷量引发服务器瘫痪
运维·服务器