搜 索

🤖 AI Skills vs MCP:从入门到放弃指南

  • 3阅读
  • 2026年02月04日
  • 0评论
首页 / AI/大数据 / 正文

Skills的概念最近又火了,这货和MCP有啥区别?怎么用?有哪些坑?本文带你一探究竟。


一、先搞清楚概念:它们到底是什么?

1.1 Skills 是什么

Skills(技能) 是 AI Agent 能够调用的能力单元的统称。
它是一个泛概念,不同框架叫法不同,本质相同:

「给 AI 一个工具,让它能干某件事」
mindmap root((AI Skills)) 广义定义 可调用的能力模块 函数/工具的集合 扩展AI边界的方式 常见形态 Tool/Function Call Plugin Action MCP Server 代表框架 OpenAI Functions LangChain Tools Semantic Kernel Plugins AutoGen Skills

1.2 MCP 是什么

MCP(Model Context Protocol) 是 Anthropic 在 2024 年底发布的开放标准协议

官方定义:MCP 是一个开放协议,让 AI 应用能以标准化方式连接数据源和工具。

用人话说:MCP 是 Skills 的"USB 标准"

在 MCP 出现之前,每个框架都有自己的插件格式,互不兼容,就像每个手机厂商用不同充电口一样让人崩溃。
MCP 想做的事就是:定一个标准,让所有 AI 工具都能插上去用

graph LR A[AI Application
Claude/GPT/Cursor] -->|MCP Protocol| B[MCP Client] B -->|标准化通信| C[MCP Server] C --> D[工具1: 文件系统] C --> E[工具2: 数据库] C --> F[工具3: API 服务] C --> G[工具N: 任意能力] style A fill:#4A90D9,color:#fff style B fill:#7B68EE,color:#fff style C fill:#50C878,color:#fff

二、Skills vs MCP:到底有什么区别?

这是本文核心,请打起精神。

2.1 一张表说清楚

维度Skills(泛概念)MCP(具体协议)
性质概念/能力单元通信标准/协议
范围所有 AI 工具能力MCP 协议定义的工具
类比「充电」这件事USB-C 充电标准
跨框架各自为政,不通用标准化,跨框架复用
实现方式因框架而异Server-Client 架构
主要使用者各 AI 框架开发者工具开发者 + AI 平台
典型代表LangChain Tools、OpenAI FunctionsClaude MCP、Cursor MCP

2.2 关系图:Skills 包含 MCP

graph TD A[AI Skills
广义技能概念] --> B[OpenAI Function Calling] A --> C[LangChain Tools] A --> D[Semantic Kernel Plugins] A --> E[MCP - Model Context Protocol] E --> E1[MCP Tools
工具调用] E --> E2[MCP Resources
资源读取] E --> E3[MCP Prompts
提示词模板] style A fill:#FF6B6B,color:#fff style E fill:#4ECDC4,color:#fff style E1 fill:#45B7D1,color:#fff style E2 fill:#45B7D1,color:#fff style E3 fill:#45B7D1,color:#fff

结论:MCP 是实现 Skills 的一种标准化方式,Skills 是比 MCP 更广的概念。


三、MCP 架构深度解析

3.1 MCP 的三大核心概念

classDiagram class MCPServer { +Tools 工具集合 +Resources 资源集合 +Prompts 提示词模板 +handle_request() +list_tools() +call_tool() } class MCPClient { +connect(server) +list_tools() +call_tool(name, args) +read_resource(uri) } class Tool { +name: string +description: string +inputSchema: JSONSchema +handler: function } class Resource { +uri: string +name: string +mimeType: string +read() string } class Prompt { +name: string +description: string +arguments: list +generate() Message[] } MCPServer "1" --> "*" Tool MCPServer "1" --> "*" Resource MCPServer "1" --> "*" Prompt MCPClient --> MCPServer : JSON-RPC 2.0

Tools(工具):AI 可以调用执行某个操作,比如「发送邮件」、「查询数据库」。
Resources(资源):AI 可以读取的数据,比如「某个文件内容」、「数据库记录」。
Prompts(提示词):预定义的提示词模板,供用户/AI 复用。

3.2 MCP 通信流程

sequenceDiagram participant User as 用户 participant LLM as AI 模型
(Claude) participant Client as MCP Client participant Server as MCP Server participant Tool as 实际工具
(文件/API/DB) User->>LLM: "帮我查一下今天的天气" LLM->>Client: 我需要调用 weather 工具 Client->>Server: tools/call {name: "get_weather", args: {city: "Dubai"}} Server->>Tool: 调用天气 API Tool-->>Server: {temp: 35, weather: "sunny"} Server-->>Client: 返回结果 Client-->>LLM: 工具执行结果 LLM-->>User: "今天迪拜天气晴,35度,建议防晒"

3.3 传输方式

MCP 支持两种传输方式,这里是第一个容易踩的坑:

graph LR subgraph Stdio传输 A1[AI App] -->|stdin/stdout| B1[MCP Server进程] note1[本地进程通信
简单但只能本地用] end subgraph SSE传输 A2[AI App] -->|HTTP + SSE| B2[MCP Server] B2 -->|SSE推送| A2 note2[网络通信
可以远程部署] end style note1 fill:#FFF3CD,stroke:#856404 style note2 fill:#D4EDDA,stroke:#155724

四、从入门到实践:动手写一个 MCP Server

4.1 环境准备

# Python 方案(推荐新手)
pip install mcp

# Node.js 方案
npm install @modelcontextprotocol/sdk

# 验证安装
python -c "import mcp; print('MCP ready!')"

4.2 最简单的 MCP Server(Python)

# my_first_mcp_server.py
# 这是你人生中第一个 MCP Server
# 请对它好一点,它还是个孩子

from mcp.server import Server
from mcp.server.models import InitializationOptions
from mcp.types import Tool, TextContent
import mcp.server.stdio

# 创建 Server 实例
app = Server("my-first-mcp-server")

# 注册工具列表
@app.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="say_hello",
            description="向指定的人打招呼(这是你的第一个 MCP 工具)",
            inputSchema={
                "type": "object",
                "properties": {
                    "name": {
                        "type": "string",
                        "description": "要打招呼的人的名字"
                    }
                },
                "required": ["name"]
            }
        ),
        Tool(
            name="calculate_bmi",
            description="计算 BMI 指数(因为我经常去健身房所以加了这个)",
            inputSchema={
                "type": "object",
                "properties": {
                    "weight_kg": {"type": "number", "description": "体重(公斤)"},
                    "height_cm": {"type": "number", "description": "身高(厘米)"}
                },
                "required": ["weight_kg", "height_cm"]
            }
        )
    ]

# 实现工具调用
@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "say_hello":
        person_name = arguments.get("name", "stranger")
        return [TextContent(
            type="text",
            text=f"你好,{person_name}!欢迎来到 MCP 的世界,从今天起你也是入门选手了 🎉"
        )]
    
    elif name == "calculate_bmi":
        weight = arguments["weight_kg"]
        height = arguments["height_cm"] / 100  # 转换为米
        bmi = weight / (height ** 2)
        
        if bmi < 18.5:
            status = "偏瘦,多吃点"
        elif bmi < 24:
            status = "正常,继续保持"
        elif bmi < 28:
            status = "偏胖,该去健身房了"
        else:
            status = "肥胖,明天就去健身房!"
        
        return [TextContent(
            type="text",
            text=f"BMI: {bmi:.1f},状态:{status}"
        )]
    
    else:
        raise ValueError(f"未知工具: {name}")

# 启动 Server
async def main():
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await app.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="my-first-mcp-server",
                server_version="0.1.0"
            )
        )

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

4.3 配置到 Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json(Mac):

{
  "mcpServers": {
    "my-first-server": {
      "command": "python",
      "args": ["/path/to/my_first_mcp_server.py"],
      "env": {
        "PYTHONPATH": "/path/to/your/project"
      }
    }
  }
}

配置完重启 Claude Desktop,你应该能看到工具图标出现了。
如果没有出现……恭喜你,开始踩坑了,请往下看。


五、进阶:带 Resources 的 MCP Server

# advanced_mcp_server.py
# 带资源读取功能,比如让 AI 读取你的博客文章

from mcp.server import Server
from mcp.types import Resource, TextContent, EmbeddedResource
import json
import os

app = Server("blog-mcp-server")

# 模拟博客文章数据库
BLOG_POSTS = {
    "post-001": {
        "title": "从入门到放弃:Go-zero 实战",
        "content": "今天我们来聊聊 Go-zero...",
        "tags": ["golang", "微服务"]
    },
    "post-002": {
        "title": "支付系统架构设计",
        "content": "作为一个每天和支付系统打交道的人...",
        "tags": ["支付", "架构"]
    }
}

# 注册资源列表
@app.list_resources()
async def list_resources() -> list[Resource]:
    resources = []
    for post_id, post in BLOG_POSTS.items():
        resources.append(Resource(
            uri=f"blog://posts/{post_id}",
            name=post["title"],
            description=f"博客文章:{post['title']}",
            mimeType="text/plain"
        ))
    return resources

# 读取资源内容
@app.read_resource()
async def read_resource(uri: str) -> str:
    # 解析 URI
    if uri.startswith("blog://posts/"):
        post_id = uri.replace("blog://posts/", "")
        if post_id in BLOG_POSTS:
            post = BLOG_POSTS[post_id]
            return json.dumps(post, ensure_ascii=False, indent=2)
    
    raise ValueError(f"资源不存在: {uri}")

六、真实案例:博客自动发布 MCP Server

这个是我实际在用的,把它集成到 n8n 工作流里,让 Claude 帮我自动发博客:

flowchart TD A[写完文章] --> B[Claude Desktop] B --> C{MCP Server} C --> D[blog_publish Tool] C --> E[platform_status Resource] D --> F[掘金 API] D --> G[知乎 API] D --> H[cnblogs API] D --> I[WordPress API] F --> J[发布成功✅] G --> K[发布成功✅] H --> L[发布成功✅] I --> M[发布成功✅] style A fill:#FFE4B5 style B fill:#4A90D9,color:#fff style C fill:#50C878,color:#fff style D fill:#7B68EE,color:#fff style E fill:#7B68EE,color:#fff
# blog_publisher_mcp.py
# 博客自动发布 MCP Server
# 警告:请提前配置好各平台的 API Token,否则你会发现发布失败的方式比你想象的多

import httpx
from mcp.server import Server
from mcp.types import Tool, TextContent

app = Server("blog-publisher")

PLATFORM_CONFIGS = {
    "juejin": {
        "api_url": "https://api.juejin.cn/content_api/v1/article/publish",
        "token_env": "JUEJIN_TOKEN"
    },
    "zhihu": {
        "api_url": "https://www.zhihu.com/api/v4/articles",
        "token_env": "ZHIHU_TOKEN"
    }
}

@app.list_tools()
async def list_tools():
    return [
        Tool(
            name="publish_blog",
            description="发布博客文章到指定平台",
            inputSchema={
                "type": "object",
                "properties": {
                    "title": {"type": "string"},
                    "content": {"type": "string", "description": "Markdown 内容"},
                    "platforms": {
                        "type": "array",
                        "items": {"type": "string", "enum": ["juejin", "zhihu", "cnblogs"]},
                        "description": "要发布的平台列表"
                    },
                    "tags": {"type": "array", "items": {"type": "string"}}
                },
                "required": ["title", "content", "platforms"]
            }
        )
    ]

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "publish_blog":
        results = []
        for platform in arguments.get("platforms", []):
            try:
                # 实际调用各平台 API(伪代码)
                result = await publish_to_platform(
                    platform=platform,
                    title=arguments["title"],
                    content=arguments["content"],
                    tags=arguments.get("tags", [])
                )
                results.append(f"✅ {platform}: 发布成功,ID={result['id']}")
            except Exception as e:
                results.append(f"❌ {platform}: 发布失败 - {str(e)}")
        
        return [TextContent(type="text", text="\n".join(results))]

async def publish_to_platform(platform, title, content, tags):
    # 实现各平台的具体发布逻辑
    # 此处省略若干行让人崩溃的代码
    pass

七、踩坑大全 🕳️

这一节是本文精华,是用真实的眼泪换来的

坑 1:stdio vs SSE 傻傻分不清

现象:配置了 MCP Server,Claude Desktop 显示连接成功,但工具调用没有任何反应。

原因:Claude Desktop 只支持 stdio 传输,你却用了 SSE 或 HTTP。

graph LR A[Claude Desktop] -->|✅ 只支持这个| B[stdio传输] A -->|❌ 不支持| C[SSE传输] A -->|❌ 不支持| D[HTTP传输] E[API调用/自建Client] -->|✅ 支持| C E -->|✅ 支持| D E -->|✅ 支持| B style B fill:#50C878,color:#fff style C fill:#FF6B6B,color:#fff style D fill:#FF6B6B,color:#fff

解决:Claude Desktop 配置用 stdio,自己的 Client 再改 SSE。


坑 2:JSON Schema 写错导致工具不可用

现象:工具注册了,但 AI 从来不调用它,或者调用时参数解析失败。

原因inputSchema 格式不对,AI 看不懂。

# ❌ 错误写法
Tool(
    name="bad_tool",
    inputSchema={
        "properties": {  # 缺少 "type": "object"
            "name": "string"  # 这不是合法的 JSON Schema
        }
    }
)

# ✅ 正确写法
Tool(
    name="good_tool",
    inputSchema={
        "type": "object",           # 必须有!
        "properties": {
            "name": {
                "type": "string",   # 必须是对象格式
                "description": "参数描述要写清楚,AI 靠这个理解"
            }
        },
        "required": ["name"]        # 明确必填字段
    }
)

坑 3:异步陷阱

现象:Server 启动后立刻崩溃,或者工具调用超时。

原因:MCP Python SDK 全程异步,你混用了同步代码。

# ❌ 在 async 函数里用同步 IO
@app.call_tool()
async def call_tool(name, args):
    import requests
    # 这会阻塞事件循环,导致超时
    result = requests.get("https://api.example.com/data")
    return [TextContent(type="text", text=result.text)]

# ✅ 用 httpx 异步版本
@app.call_tool()
async def call_tool(name, args):
    import httpx
    async with httpx.AsyncClient() as client:
        result = await client.get("https://api.example.com/data")
    return [TextContent(type="text", text=result.text)]

坑 4:路径问题(Windows 用户专属噩梦)

现象:Mac/Linux 正常,Windows 上 MCP Server 启动失败。

原因:路径分隔符、Python 环境变量、command 配置方式都不同。

// ❌ Mac 配置直接复制到 Windows 用
{
  "command": "python",
  "args": ["/Users/joey/mcp/server.py"]
}

// ✅ Windows 正确配置
{
  "command": "C:\\Python311\\python.exe",
  "args": ["C:\\Users\\Joey\\mcp\\server.py"]
}

// ✅ 更好的方式:用 uv 管理环境
{
  "command": "uv",
  "args": ["run", "--project", "C:\\mcp-project", "server.py"]
}

坑 5:description 写的太烂,AI 不知道何时调用

现象:明明有对应工具,AI 却自己瞎编数据,不去调用工具。

原因:工具描述太模糊,AI 不知道什么时候该用。

# ❌ 描述太烂
Tool(
    name="get_data",
    description="获取数据"
    # AI:获取什么数据?我怎么知道该用你?
)

# ✅ 描述清晰,触发条件明确
Tool(
    name="get_payment_status",
    description="""查询支付交易状态。
    当用户询问某笔交易的状态、支付是否成功、转账进度时调用此工具。
    支持通过交易ID(transaction_id)或订单号(order_no)查询。
    返回交易状态、金额、时间戳等完整信息。""",
)

坑 6:MCP Server 日志去哪了?

现象:出了问题完全不知道哪里错了,因为 Claude Desktop 吞掉了所有输出。

解决:把日志写到文件:

import logging

# 不能用 print,Claude Desktop 会把 stdout 当协议数据
# 必须写文件或者 stderr
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('/tmp/mcp_debug.log'),
        logging.StreamHandler(sys.stderr)  # stderr 是安全的
    ]
)

logger = logging.getLogger(__name__)

坑 7:工具参数验证不够严格

现象:AI 传了错误格式的参数,Server 报了一个让人看不懂的错误。

最佳实践:用 Pydantic 做参数验证:

from pydantic import BaseModel, validator

class PublishArgs(BaseModel):
    title: str
    content: str
    platforms: list[str]
    
    @validator('platforms')
    def validate_platforms(cls, v):
        valid = {'juejin', 'zhihu', 'cnblogs'}
        invalid = set(v) - valid
        if invalid:
            raise ValueError(f"不支持的平台: {invalid},有效值: {valid}")
        return v

@app.call_tool()
async def call_tool(name: str, arguments: dict):
    try:
        args = PublishArgs(**arguments)
    except Exception as e:
        return [TextContent(type="text", text=f"参数错误: {e}")]

八、最佳实践 & 设计模式

8.1 MCP Server 设计原则

graph TD A[好的 MCP Server] --> B[单一职责
一个Server管一类功能] A --> C[描述清晰
让AI知道何时调用] A --> D[错误友好
返回人类可读的错误] A --> E[幂等设计
重复调用不出问题] A --> F[超时处理
别让AI傻等] style A fill:#4A90D9,color:#fff style B fill:#50C878,color:#fff style C fill:#50C878,color:#fff style D fill:#50C878,color:#fff style E fill:#50C878,color:#fff style F fill:#50C878,color:#fff

8.2 与 LangChain Tools 的对比

graph LR subgraph LangChain方案 A[LangChain App] -->|Python函数调用| B[LangChain Tool] B -->|紧耦合| C[具体实现] end subgraph MCP方案 D[Any AI App] -->|标准协议| E[MCP Client] E -->|JSON-RPC| F[MCP Server] F -->|解耦| G[具体实现] end style E fill:#4ECDC4,color:#fff style F fill:#4ECDC4,color:#fff

LangChain Tools 优点:简单直接,在 LangChain 生态里无缝集成。
MCP 优点:跨框架复用,一次开发多处使用,社区已有大量现成 Server。

8.3 现成的 MCP Server 生态

不用重复造轮子,这些已经有成熟实现了:

类别工具地址
文件系统filesystem官方维护
数据库sqlite / postgres官方维护
Gitgit操作官方维护
浏览器puppeteer官方维护
搜索brave-search官方维护
GitHub仓库操作官方维护
Slack消息/频道官方维护
记忆memory官方维护

完整列表:https://github.com/modelcontextprotocol/servers


九、学习路径:从入门到(尝试)精通

graph TD A[🌱 入门阶段] --> A1[理解 MCP 概念] A1 --> A2[配置 Claude Desktop
使用官方 MCP Server] A2 --> A3[运行 Hello World Server] A3 --> B[📚 基础阶段] B --> B1[实现带 Tools 的 Server] B1 --> B2[添加 Resources 支持] B2 --> B3[错误处理 & 日志] B3 --> C[🚀 进阶阶段] C --> C1[SSE 传输远程部署] C1 --> C2[集成第三方 API] C2 --> C3[构建完整业务 Server] C3 --> D[🏆 精通阶段] D --> D1[多 Server 协作架构] D1 --> D2[性能优化 & 监控] D2 --> D3[开源贡献 & 生态] D3 --> E[😱 放弃阶段] E --> E1[发现新的更好的方案] E1 --> E2[重新入门] E2 --> A style A fill:#90EE90,color:#000 style B fill:#87CEEB,color:#000 style C fill:#DDA0DD,color:#000 style D fill:#FFD700,color:#000 style E fill:#FF6B6B,color:#fff

推荐学习资源


十、总结

graph LR A[学会了什么] --> B[Skills是泛概念
MCP是具体协议] A --> C[MCP = AI工具的USB标准] A --> D[Server-Client架构
JSON-RPC通信] A --> E[三大核心: Tools/Resources/Prompts] A --> F[踩坑经验
= 宝贵财富] style A fill:#4A90D9,color:#fff style F fill:#FF6B6B,color:#fff

一句话总结

Skills 是目标,MCP 是实现目标的最优路径之一。
先理解 Skills 的概念,再用 MCP 的标准把它实现出来,就这么简单。
(当然,实际做起来不简单,否则你也不会来看这篇文章)

评论区
暂无评论
avatar