MCP入门,看完这篇就够了

转载请注明出处❤️

作者:测试蔡坨坨

原文链接:caituotuo.top/9cf8820a.html


你好,我是测试蔡坨坨。

最近在学习MCP,一开始也是一脸懵,文档一大堆,概念也挺抽象。但摸索了一圈之后,其实发现它并没有那么高冷,掌握了基本概念和用法,就能快速搭建出一套模块化的系统架构。

于是,顺手整理了一份极简入门教程,分享给和我一样想上手但不知如何下手的朋友们。

1 什么是MCP?

1.1 MCP简介

MCP(Model Context Protocol,模型上下文协议)

MCP 是一个由 Anthropic (Claude模型的公司)开源的标准化协议,让大模型能够以统一的方式连接和访问各种数据、工具和服务。

通过这种方式,可以拓展 LLM 的能力边界,可以将其视为一个通用的适配器,让 LLM 能够接入庞大的互联网资源网络,增强其功能并开启新的可能性。

1.2 MCP架构

MCP 官网:https://modelcontextprotocol.io/introduction

MCP 采用 客户端 - 服务器 模式运行,其中 MCP 宿主(例如:Claude 桌面应用、代码编辑器 Cursor、代码编辑插件 Cline …)可以连接到多个 MCP 服务器。每个服务器通过标准化协议暴露特定的功能,使 LLM 能够访问各种功能。MCP 就像 AI 应用程序的 USB-C 接口,为 AI 模型提供了一种标准化的方式来连接不同的数据源和工具。

MCP 中的三个角色:

  • MCP 宿主:使用 MCP 连接各种资源的应用程序,例如:AI 助手、开发环境和专门的 AI 工具,一个宿主通常包含多个MCP客户端。
  • MCP 客户端:宿主内部的组件,负责与各个MCP服务器建立直接连接。客户端和服务器保持 1:1 的连接关系。
  • MCP 服务器:通过 MCP 框架提供特定功能的轻量级程序。这些服务器可以访问本地和远程资源。

MCP 的一些概念:

  • 资源

    • 资源是 MCP 中的基本元素,允许服务器向 LLM 暴露数据和内容。包括各种类型的信息,例如:文件内容、数据库记录、API 响应,甚至实时系统数据。资源设计为应用程序可控的,这意味着客户端应用程序可以决定如何以及何时使用它们。

    • MCP 支持两种类型的资源:

      • 文本资源:适用于源代码、配置文件、日志文件和其他文本数据
      • 二进制资源:适用于图像、PDF、音频文件、视频文件和其他非文本格式
    • 资源 URI

      • 资源使用以下格式的 URI 进行标识:

        1
        [协议]://[主机]/[路径]
      • 例如:

        1
        2
        3
        file:///home/user/caituotuo.pdf # 文件
        postgres://database/customers/schema # 数据库
        screen://localhost/display

      协议和路径结构由 MCP 服务器实现定义。服务器可以定义自己的自定义 URI 方案。

  • 提示词

    • 提示词通常是可重用的模板,用于指导 LLM 有效地与 MCP 服务器交互。

    • 结构:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      {
      name: string; // 提示词的唯一标识
      description?: string;
      arguments?: [
      {
      name: string; // 参数的唯一标识
      description?: string;
      required?: boolean;
      }
      ]
      }
    • 发现提示词

      客户端可以通过 prompts/list 端点发现可用的提示词:

      响应:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      {
      prompts: [
      {
      name: "translate-into-chinese";
      description: "将内容翻译成中文";
      arguments: [
      {
      name: "content";
      description: "需要翻译的内容";
      required: true;
      }
      ]
      }
      ]
      }
  • 工具

    • 工具使 LLM 能够通过 MCP 服务器执行操作。与主要提供数据的资源不同,工具设计用于执行计算并产生副作用。

    • 工具的定义:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      {
      name: string; // 工具的唯一标识
      description?: string;
      inputSchema?: [ // 工具参数 JSON Schema
      {
      type: object;
      properties: { ... } // 工具特定的参数
      }
      ]
      }
    • 实现工具

  • 传输层

    传输层定义了 MCP 客户端和服务器之间的通信通道,促进消息和数据的交换。

    消息格式:JSON-RPC 2.0

    内置两种传输类型:

    • stdio:通过标准输入/输出流实现通信,例如:本地集成、命令行工具。
    • SSE:服务器发送事件,通过 HTTP POST 请求实现服务器到客户端的流式传输,例如:需要服务器到客户端的流式传输、在受限网络中工作、实现简单更新。

2 Claude Desktop

最典型的 MCP 客户端就是 Claude Desktop,它是 Anthropic 开发的 AI 助手,内置支持 MCP。

2.1 配置

按照以下步骤配置 Claude Desktop 以使用 MCP 服务器:

  1. 下载和安装

    官网:https://claude.ai/download

    支持 macOS 和 Windows 版:

  2. 创建配置文件

    • 打开 Claude 菜单并选择“设置”

    • 导航到“开发者”选项卡,点击“编辑配置”

      第一次会创建一个名为 claude_desktop_config.json 的配置文件:

  3. 添加服务器配置

    编辑配置文件,添加 mcp 服务:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    {
    "mcpServers": {
    "filesystem": {
    "command": "npx", // 这里用到了npx,需要确保计算机安装了Node.js
    "args": [
    "-y",
    "@modelcontextprotocol/server-filesystem",
    "/Users/caihesheng/Desktop/myFiles/blog/source/_posts"
    ]
    }
    }
    }

    确保路径指向有效的目录,并且可以添加多个目录。

  4. 重启 Claude

    重启 Claude Desktop 以应用更改,可以看到运行中的 filesystem 服务:

    点击 Claude Desktop 对话界面中的 Search and tools 图标夹可以查看 MCP 服务器提供的工具:

2.2 使用

首先让它列出所有在 _posts 文件下的所有文件:

1
List all the files in my _posts folder.

它会尝试调用 filesystem 服务的 list_allowed_directories 这个工具:

点击授权,Claude 会访问到我指定的目录,它能够成功地发现目录下的所有文件:

接着让它给出指定文件的内容:

1
Show me the content of  8分钟搞懂Java中的各种锁.md

可以看到它成功地调用 read_file 这个工具读取到文章内容,并对内容进行总结:

这样我们就成功地完成了 MCP 服务器的配置,并通过 Claude Desktop 验证了工具工作一切正常。

除此之外,MCP 官网还列出了许多可以用的服务,可以根据需要集成到自己的 MCP 客户端:

https://modelcontextprotocol.io/examples

同时,在 MCP 官方的 servers 仓库中也列出了目前市面上绝大多数的官网和三方支持的 mcp 服务:

https://github.com/modelcontextprotocol/servers

3 准备 UV 开发环境

macOS 和 Linux:

1
curl -LsSf https://astral.sh/uv/install.sh | sh

1
2
3
4
5
6
7
8
9
10
11
12
downloading uv 0.7.11 aarch64-apple-darwin
no checksums to verify
installing to /Users/caihesheng/.local/bin
uv
uvx
everything's installed!

To add $HOME/.local/bin to your PATH, either restart your shell or run:

source $HOME/.local/bin/env (sh, bash, zsh)
source $HOME/.local/bin/env.fish (fish)
caihesheng@JokerMacBookProM3Max ~ %

重启终端,运行 uv --version 查看是否安装成功:

4 MCP 服务器开发

开始构建你的第一个 MCP 服务器,这里用到了一个 Python 开发包 yfinance 基于雅虎财经的信息和数据来获取公司的概要信息和新闻。

它提供两个工具:

  • get_summary:获取公司的概要信息
  • get_new:获取公司的新闻

通过这个服务器,Claude 桌面应用将能够回答与公司财务信息和新闻相关的查询。

4.1 安装 Python SDK

1
pip install mcp
1
pip install yfinance

4.2 代码开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import yfinance as yf
from mcp.server.fastmcp import FastMCP

# 初始化 FastMCP 服务器,并自定义名字
mcp = FastMCP("yahoo-finance")


# 通过 @mcp.tool() 装饰器,定义一个工具函数
@mcp.tool()
async def get_summary(ticker: str) -> str:
"""Get company summary by ticket.

Args:
ticker: Company ticker (e.g. AAPL, GOOGL)
"""

ticker = yf.Ticker(ticker)

summary = ticker.info["longBusinessSummary"]

return summary.strip()


@mcp.tool()
async def get_news(ticker: str) -> str:
"""Get company news by ticket.

Args:
ticker: Company ticker (e.g. AAPL, GOOGL)
"""

ticker = yf.Ticker(ticker)
news = ticker.news
return "\n\n".join([f"{n['content']['summary']}\n{n['content']['canonicalUrl']['url']}" for n in news])


if __name__ == "__main__":
mcp.run(transport='stdio')

4.3 在 Claude 中测试 MCP 服务器

4.3.1 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"mcpServers": {
"yahoo-finance": {
"command": "/Users/caihesheng/.local/bin/uv",
"args": [
"--directory",
"/Users/caihesheng/Desktop/myFiles/code/yahoo-finance",
"run",
"yahoo-finance.py"
]
}
}
}

配置完成后,重启 Claude,可以看到新配置的工具:

4.3.2 使用

5 MCP 客户端开发

MCP 客户端负责连接到 MCP 服务器。列出可用的资源和工具,并处理 LLM 与服务器之间的通信。构建 MCP 客户端涉及实现服务器连接、工具列表、工具使用和 LLM 集成等功能。

5.1 安装 Python SDK

1
pip install mcp
1
pip install anthropic
1
pip install python-dotenv

5.2 配置环境变量

.env 文件:

1
2
3
ANTHROPIC_API_KEY=
ANTHROPIC_MODEL=claude-3-5-sonnet-20241022 # 模型设置
ANTHROPIC_BASE_URL=https://api.anthropic.com # 如果使用非官方的 Anthropic API 的 Claude API,则需配置

5.3 代码开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
import asyncio
import os
from contextlib import AsyncExitStack
from typing import Optional

from anthropic import Anthropic
from dotenv import load_dotenv
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

load_dotenv()


class MCPClient:
def __init__(self):
# Initialize session and client objects
self.session: Optional[ClientSession] = None
self.exit_stack = AsyncExitStack()
self.anthropic = Anthropic()
self.model = os.getenv("ANTHROPIC_MODEL")

async def connect_to_server(self, server_script_path: str):
"""连接到 MCP 服务器

参数:
server_script_path: 服务器脚本路径 (.py or .js)
"""
is_python = server_script_path.endswith('.py')
is_js = server_script_path.endswith('.js')
if not (is_python or is_js):
raise ValueError("Server script must be a .py or .js file")

command = "python" if is_python else "node"
server_params = StdioServerParameters(
command=command,
args=[server_script_path],
env=None
)

stdio_transport = await self.exit_stack.enter_async_context(stdio_client(server_params)) # 使用stdio传输协议构建一个客户端
self.stdio, self.write = stdio_transport
self.session = await self.exit_stack.enter_async_context(ClientSession(self.stdio, self.write)) # 初始化会话,通过ClientSession类实现

await self.session.initialize()

# 调用list_tools()列出可用工具
response = await self.session.list_tools()
tools = response.tools
print("\nConnected to server with tools:", [tool.name for tool in tools])

async def process_query(self, query: str) -> str:
"""使用 Claude 和可用工具处理查询"""
messages = [
{
"role": "user",
"content": query # 用户提问
}
]

# 通过会话获取目前 MCP 服务器支持的工具列表
response = await self.session.list_tools()
# 转成 Claude 模型支持的工具列表参数
available_tools = [{
"name": tool.name,
"description": tool.description,
"input_schema": tool.inputSchema
} for tool in response.tools]

# 初始化 Claude API 调用
response = self.anthropic.messages.create(
model=self.model,
max_tokens=1000,
messages=messages, # 用户的 query 以消息数组的形式交给 messages 参数
tools=available_tools # 会将目前 MCP 支持的工具交给 tools 参数
)

# 处理响应和工具调用
tool_results = []
final_text = []

for content in response.content:
if content.type == 'text':
final_text.append(content.text)
# 判断响应中是否有 tool_use 的类型
elif content.type == 'tool_use':
tool_name = content.name # 工具名字
tool_args = content.input # 工具调用参数

# 再通过 call_tool() 函数 执行工具调用
result = await self.session.call_tool(tool_name, tool_args)
tool_results.append({"call": tool_name, "result": result})
final_text.append(f"[Calling tool {tool_name} with args {tool_args}]")

# Continue conversation with tool results
if hasattr(content, 'text') and content.text:
messages.append({
"role": "assistant",
"content": content.text
})
# 告诉模型工具调用的结果
messages.append({
"role": "user",
"content": result.content
})

# 从 Claude 获取下一个响应
response = self.anthropic.messages.create(
model=self.model,
max_tokens=1000,
messages=messages,
)

final_text.append(response.content[0].text)

return "\n".join(final_text)

async def chat_loop(self):
"""Run an interactive chat loop"""
print("\nMCP Client Started!")
print("Type your queries or 'quit' to exit.")

while True:
try:
query = input("\nQuery: ").strip()

if query.lower() == 'quit':
break

response = await self.process_query(query)
print("\n" + response)

except Exception as e:
print(f"\nError: {str(e)}")

async def cleanup(self):
"""Clean up resources"""
await self.exit_stack.aclose()


async def main():
if len(sys.argv) < 2:
# 服务器路径
print("Usage: python client.py <path_to_server_script>")
sys.exit(1)

client = MCPClient()
try:
await client.connect_to_server(sys.argv[1])
await client.chat_loop()
finally:
await client.cleanup()


if __name__ == "__main__":
import sys

asyncio.run(main())

5.4 运行 MCP 客户端服务

5.4.1 运行

运行命令:

1
uv run mcp-client.py /Users/caihesheng/Desktop/myFiles/code/yahoo-finance/yahoo-finance.py

可以看到成功运行了 MCP 服务器 yahoo-finance.py,并且获取了工具列表get_summary、get_news:

5.4.2 使用

进行提问,可以看到它会先去拉取工具列表(ListToolsRequest),然后调用工具(CallToolRequest):

基于工具调用的结果,大模型推理出最终答案:

6 MCP Inspector

MCP Inspector 是一个开发工具,允许我们通过交互式调用工具测试和检查 MCP 服务器。

它提供了一个用户界面,可以在其中测试所有 MCP 功能,包括资源、提示词和工具,查看可用资源及其内容,调试服务响应,并验证自己的实现是否按预期工作。

6.1 运行

Inspector 可以通过 npx 直接运行,无需安装:

1
npx @modelcontextprotocol/inspector <command> <arg1> <arg2>
1
npx @modelcontextprotocol/inspector uv --directory /Users/caihesheng/Desktop/myFiles/code/yahoo-finance run yahoo-finance.py

成功启动后,可以看到它运行在6274端口:

6.2 使用

浏览器访问:http://127.0.0.1:6274

点击 Connect 连接到 MCP 服务器: