掘金 人工智能 05月13日 18:18
MCP学习笔记
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

MCP(模型上下文协议)旨在为AI应用提供统一的上下文提供方式,类似于USB-C接口为设备连接外设提供标准。它采用客户端-服务器架构,通过MCP客户端连接宿主应用和MCP服务器,实现LLM与各种数据源和工具的即插即用集成。MCP支持多种传输机制,包括标准输入输出和HTTP SSE,并定义了请求、结果、错误和通知等消息类型。通过资源、提示词和工具等基本元素,MCP为构建Agent和复杂工作流提供了灵活、可扩展的架构,助力LLM应用高效对接数据和工具。

🔑 **MCP的核心架构**:MCP采用客户端-服务器架构,宿主应用通过MCP客户端与MCP服务器连接,服务器负责暴露数据、工具和提示词,实现LLM应用与各种数据源的无缝通信。

🔗 **MCP的传输层规范**:MCP支持多种传输机制,包括适用于本地进程间通信的标准输入输出传输(Stdio)和适用于远程通信的HTTP SSE传输,所有传输均采用JSON-RPC 2.0协议交换消息。

🧩 **MCP的基本元素**:MCP包含资源(Resources)、提示词(Prompts)和工具(Tools)等基本元素。资源允许服务器暴露数据和内容,提示词模板使服务器能够定义可重用的提示模板和工作流程,工具则使服务器能够向客户端暴露可执行的功能。

2025年5月12日

MCP简介

MCP(Model Context Protocol)是一个开放协议,旨在标准化应用程序向大语言模型(LLMs)提供上下文的方式。您可以将 MCP 想象成 AI 应用的 USB-C 接口——正如 USB-C 为设备连接各类外设提供了统一标准,MCP 也为 AI 模型连接不同数据源和工具建立了标准化桥梁。

为什么选择 MCP?

MCP 帮助在 LLMs 之上构建Agent和复杂工作流。由于 LLMs 需要频繁对接数据和工具,MCP 提供:

核心架构

重点理解MCP的CS架构设计传输层规范。

模型上下文协议 (MCP) 建立在灵活、可扩展的架构之上,可实现 LLM 应用程序和集成之间的无缝通信。

概述

MCP 采用客户端-服务器架构,支持宿主程序连接多个服务器:

flowchart LR    subgraph "Your Computer"        Host["Host with MCP Client\n(Claude, IDEs, Tools)"]        S1["MCP Server A"]        S2["MCP Server B"]        S3["MCP Server C"]        Host <-->|"MCP Protocol"| S1        Host <-->|"MCP Protocol"| S2        Host <-->|"MCP Protocol"| S3        S1 <--> D1[("Local\nData Source A")]        S2 <--> D2[("Local\nData Source B")]    end    subgraph "Internet"        S3 <-->|"Web APIs"| D3[("Remote\nService C")]    end
flowchart LR    subgraph "Host"        client1[MCP Client]        client2[MCP Client]    end    subgraph "Server Process"        server1[MCP Server]    end    subgraph "Server Process"        server2[MCP Server]    end    client1 <-->|Transport Layer| server1    client2 <-->|Transport Layer| server2

核心组件

核心组件包括:协议层、传输层、消息类型

协议层

协议层负责消息封装、请求/响应关联及上层的通信模式

// 处理client和server通信的MCP sessioninterface McpSession {// 向模型对应方发送请求,并期望获得类型为 T 的响应。<T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef);// 向模型client或server发送不带参数的通知default Mono<Void> sendNotification(String method) {return sendNotification(method, null);}// 向模型client或server发送带参数的通知Mono<Void> sendNotification(String method, Object params);// 关闭session并异步释放全部关联的资源Mono<Void> closeGracefully();// 关闭session并释放全部关联的资源void close();}

传输层

传输层负责客户端与服务端的实际通信。

MCP 支持多种传输机制: 

    标准输入输出传输(Stdio)
    HTTP SSE 传输

所有传输均采用JSON-RPC 2.0 协议交换消息。

JSON-RPC:www.jsonrpc.org/

JSON-RPC示例:

服务端请求 --> {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}客户端接收 <-- {"jsonrpc": "2.0", "result": 19, "id": 1}服务端请求 --> {"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 2}客户端接收 <-- {"jsonrpc": "2.0", "result": 19, "id": 2}

消息类型

MCP 定义以下主要消息类型: 

1. **请求(Requests)**需要对方响应

record JSONRPCRequest (  // ...  String method,  // 方法标识  Object params   // 请求参数)

2. **结果(Results)**表示请求成功响应

record JSONRPCResponse (  // ...  Object result,  // 结果数据  JSONRPCError error)

3. **错误(Errors)**表示请求失败:

record JSONRPCError (  int code,        // 错误代码  String message,  // 错误描述  Object data)

4. **通知(Notifications)**无需响应的单向消息

record JSONRPCNotification (  // ...  String method,  Object params)

连接生命周期

一、初始化阶段

    客户端发送包含协议版本与能力的initialize请求

    服务端返回协议版本与能力声明

    客户端发送initialized通知确认

    开始正常消息交换

sequenceDiagram    participant Client    participant Server    Client->>Server: initialize request    Server->>Client: initialize response    Client->>Server: initialized notification    Note over Client,Server: Connection ready for use

二、消息交换阶段

初始化完成后支持以下模式:

三、终止阶段

连接可通过以下方式终止:

错误处理

MCP 定义标准错误代码:

class ErrorCodes {    // Standard JSON-RPC error codes    int PARSE_ERROR = -32700;    int INVALID_REQUEST = -32600;    int METHOD_NOT_FOUND = -32601;    int INVALID_PARAMS = -32602;    int INTERNAL_ERROR = -32603;}

SDK 与应用可自定义高于 -32000 的错误代码。

错误通过以下方式传递:

实现示例

基础 MCP 服务端实现示例:

var transport = new StdioServerTransportProvider();// Configure server capabilities with resource supportvar capabilities = McpSchema.ServerCapabilities.builder()        .resources(false, true) // No subscribe support, but list changes notifications        .tools(true) // Tool support with list changes notifications        .prompts(true) // Prompt support with list changes notifications        .logging() // Logging support        .build();// Create the server with both tool and resource capabilitiesvar server = McpServer.async(transport)        .serverInfo("MCP Demo Server", "1.0.0")        .capabilities(capabilities)        .resources(Collections.emptyList())        .prompts(Collections.emptyList())        .tools(Collections.emptyList())        .build();

最佳实践

    本地通信
    远程通信

基本元素

MCP的基本元素包括:

其中,以Resource、Prompt、Tool为核心元素。

资源(Resources)

资源是模型上下文协议(Model Context Protocol, MCP)中的核心基本元素,它允许服务器暴露数据和内容,供客户端读取并用作LLM交互的上下文。

概述

资源代表MCP服务器希望提供给客户端的任何类型的数据。这可以包括:

每个资源都由唯一的URI标识,可以包含文本或二进制数据。

资源URI

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

[协议]://[主机]/[路径]

例如:

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

资源类型

资源可以包含两种类型的内容:

文本资源

文本资源包含UTF-8编码的文本数据。例如:

二进制资源

二进制资源包含以base64编码的原始二进制数据。例如:

资源发现

客户端(Client)可以通过两种主要方式发现可用资源

直接资源

服务器通过resources/list端点暴露具体资源的列表。

record Resource(    String uri,             // 资源的唯一标识符    String name,            // 人类可读的名称    String description,     // 可选描述    String mimeType,        // 可选MIME类型    Annotations annotations // 可选的注解信息) implements Annotated {}
资源模版

对于动态资源,服务器可以暴露URI模板,客户端可以用它来构建有效的资源URI:

record ResourceTemplate(    String uriTemplate,    // 遵循RFC6570的URI模板,例如:/user/{userId}    String name,    String description,    String mimeType,    Annotations annotations) implements Annotated {}

读取资源

要读取资源,客户端需发送带有资源URI的resources/read请求。

服务器以资源内容列表响应:

// 返回的资源结构record ReadResourceResult(    List<ResourceContents> contents    // 资源列表) {}// 文本资源内容record TextResourceContents(    String uri,    String mimeType,    String text    // 文本数据) implements ResourceContents {}// 二进制资源内容record BlobResourceContents(    String uri,    String mimeType,    String blob    // 二进制数据) implements ResourceContents {}

资源更新通知

MCP通过两种机制支持资源的实时更新:

列表变更

服务器可以通过notifications/resources/list_changed通知客户端其可用资源列表的变更。

内容变更

客户端可以订阅特定资源的更新:

    客户端发送带有资源URI的resources/subscribe

    当资源变更时,服务器发送notifications/resources/updated

    客户端可以通过resources/read获取最新内容

    客户端可以通过resources/unsubscribe取消订阅

最佳实践

    为动态内容实现资源模板

    对频繁变更的资源使用订阅

    考虑对大型资源列表进行分页

    适当时缓存资源内容

提示词(Prompts)

提示词模板使服务器能够定义可重用的提示模板和工作流程,客户端可以轻松地向用户和LLM呈现这些内容。它们提供了一种强大的方式来标准化和共享常见的LLM交互。

Tips:提示模板设计为用户控制的,这意味着它们从服务器暴露给客户端时,目的是让用户能够明确地选择使用它们。

概述

MCP中的提示模板是预定义的模板,可以:

提示词模版结构

// 提示词模版结构record Prompt(    String name,    String description,    List<PromptArgument> arguments    // 可选的参数列表) {}// 提示词模版参数record PromptArgument(    String name,    String description,    Boolean required    // 参数是否必填) {}

发现提示词模版

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

服务端响应:

record ListPromptsResult(    List<Prompt> prompts,    // 提示词模版列表    String nextCursor        // 分页查询使用的游标) {}

使用提示词模版

要使用提示模板,客户端需发送prompts/get请求

record GetPromptRequest(    String name,    Map<String, Object> arguments) implements Request {}

响应的提示词内容有三种类型:

// 请求{  method: "prompts/get",  params: {    name: "analyze-code",    arguments: {      language: "python"    }  }}// 响应{  description: "分析Python代码以寻找潜在的改进",  messages: [    {      role: "user",      content: {        type: "text",        text: "请分析以下Python代码以寻找潜在的改进:\n\n```python\ndef calculate_sum(numbers):\n    total = 0\n    for num in numbers:\n        total = total + num\n    return total\n\nresult = calculate_sum([1, 2,3, 4, 5])\nprint(result)\n```"      }    }  ]}

工具(Tools)

工具是MCP中的一种强大的基本元素,它使服务器能够向客户端暴露可执行的功能。通过工具,LLM可以与外部系统交互,执行计算,并在现实世界中采取行动。

工具被设计为由模型控制,这意味着工具从服务器暴露给客户端时,其目的是让AI模型能够自动调用它们。

概述

MCP中的工具允许服务器暴露可执行函数,这些函数可被客户端调用并由LLM使用来执行操作。工具的关键方面包括:

与资源类似,工具由唯一名称标识,并可以包含描述来指导其使用。然而,与资源不同,工具代表可以修改状态或与外部系统交互的动态操作。

工具定义结构

{  name: string;          // 工具的唯一标识符  description?: string;  // 人类可读的描述  inputSchema: {         // 工具参数的JSON Schema    type: "object",    properties: { ... }  // 工具特定的参数  },  annotations?: {        // 关于工具行为的可选提示    title?: string;      // 工具的人类可读标题    readOnlyHint?: boolean;    // 如果为true,工具不会修改其环境    destructiveHint?: boolean; // 如果为true,工具可能执行破坏性更新    idempotentHint?: boolean;  // 如果为true,使用相同参数重复调用不会产生额外效果    openWorldHint?: boolean;   // 如果为true,工具与外部实体交互  }}

inputSchema结构:

record JsonSchema(    String type,                       // 数据类型    Map<String, Object> properties,    // key:参数名称, value:参数的描述Schema    List<String> required,             // 必填的参数名称集合    Boolean additionalProperties,    Map<String, Object> defs,    Map<String, Object> definitions) {}

工具示例

以下是服务器可以提供的工具类型示例:

系统操作

与本地系统交互的工具:

{  name: "execute_command",  description: "运行shell命令",  inputSchema: {    type: "object",    properties: {      command: { type: "string" },      args: { type: "array", items: { type: "string" } }    }  }}
API集成

封装外部API的工具:

{  name: "github_create_issue",  description: "创建GitHub issue",inputSchema: {    type: "object",    properties: {      title: { type: "string" },      body: { type: "string" },      labels: { type: "array", items: { type: "string" } }    }  }}
数据处理

转换或分析数据的工具:

{  name: "analyze_csv",  description: "分析CSV文件",  inputSchema: {    type: "object",    properties: {      filepath: { type: "string" },      operations: {        type: "array",        items: {          enum: ["sum", "average", "count"]        }      }}  }}

工具发现和更新

MCP支持动态工具发现:

    客户端可以随时列出可用工具

    服务器可以使用notifications/tools/list_changed通知客户端工具变更

    工具可以在运行时添加或移除

    工具定义可以更新(但应谨慎进行)

错误处理

工具错误应在结果对象中报告,而不是作为MCP协议级别的错误。这允许LLM查看并可能处理错误。当工具遇到错误时:

    在结果中设置isErrortrue

    content数组中包含错误详情

try {  // Tool operation  const result = performOperation();  return {    content: [      {        type: "text",        text: `Operation successful: ${result}`      }    ]  };} catch (error) {  return {    isError: true,    content: [      {        type: "text",        text: `Error: ${error.message}`      }    ]  };}

最佳实践

    提供清晰、描述性的名称和描述

    为参数使用详细的JSON Schema定义

    在工具描述中包含示例,以演示模型应如何使用它们

    让工具的功能更聚焦和原子

采样(Sampling)

采样是MCP的一项强大功能,它允许服务器通过客户端请求LLM补全内容,从而实现复杂的智能代理行为,同时保持安全性和隐私性。

采样工作原理

采样流程遵循以下步骤:

    服务器向客户端发送sampling/createMessage请求

    客户端审核请求并可以修改它

    客户端使用LLM生成补全内容

    客户端审核LLM生成的内容

    客户端将结果返回给服务器

这种的设计确保用户能够控制LLM看到和生成的内容。

根源(Roots)

Roots(根源)是MCP中定义服务器可操作边界的概念。它提供了一种方式,使得客户端能够告知服务器相关资源及其位置。

Roots是客户端建议服务器应关注的URI。当客户端连接到服务器时,它会声明服务器应该使用哪些根源。虽然主要用于文件系统路径,但根源可以是任何有效的URI,包括HTTP URL。例如:

file:///home/user/projects/myapphttps://api.example.com/v1

示例

{  "roots": [    {      "uri": "file:///home/user/projects/frontend",      "name": "前端代码库"    },    {      "uri": "https://api.example.com/v1",      "name": "API端点"    }  ]}

MCP实践

自己编写一个MCP Server

官方提供了多种语言的SDK:

但是不同语言的SDK的质量差距较大,例如java-sdk相比python-sdk就垃圾不少。推荐使用python-sdk。

第一步,安装python项目的环境管理工具uv

curl -LsSf https://astral.sh/uv/install.sh | sh# 或 通过 brew 安装brew install uv

第二步,设置python项目环境

# 为我们的项目创建一个新目录uv init mcp-server-democd mcp-server-demo# 创建虚拟环境并激活它uv venvsource .venv/bin/activate# 安装依赖uv add "mcp[cli]"# 创建我们的MCP服务器文件touch python-mcp-test.py

第三步,编写server代码,代码示例如下

# python-mcp-test.pyfrom mcp.server.fastmcp import FastMCP# 创建一个 Servermcp = FastMCP("python-mcp-test")# 添加一个工具@mcp.tool(description="整数加法计算器")def add(a: int, b: int) -> int:    """Add two numbers"""    return a + b# 添加一个资源@mcp.resource("files:///documents/QLExpress.md")def get_ql_express_knowledge() -> str:    """QL express knowledge"""    with open('resources/QLExpress.md', 'r') as f:        return f.read()# 添加一个提示词@mcp.prompt(description="查询部门")def query_dept(dept_no: str) -> str:    """Query department"""    return f"查询编号为{dept_no}的部门信息"if __name__ == "__main__":    mcp.run()

第四步,调试server

运行命令,然后在浏览器页面进行调试

uv run mcp dev python-mcp-test.py

以HSF服务作为MCP Server

请参考文章:ata.atatech.org/articles/11…

以Cline作为MCP Host

第一步,安装VS Code,并在VS Code上下载Cline

第二步,开启MCP功能

第三步,连接LLM,以连接DeepSeek为例

第四步,配置MCP Server的连接信息。此处以连接自定义MCP Server为例,也可以使用市场上现成的MCP Server。

示例:

Java MCP Server:

{  "mcpServers": {    "spring-ai-mcp-rpc": {      "command": "java",      "args": [        "-Dspring.ai.mcp.server.stdio=true",        "-jar",        "// todo jar包文件绝对路径,例如:/Users/yuguo/tools/mvn_repository/org/example/test-demo/0.0.1-SNAPSHOT/test-demo-0.0.1-SNAPSHOT.jar"      ],      "transportType": "stdio"    }  }}

Python MCP Server:

{  "mcpServers": {    "python-mcp-test": {      "command": "/opt/homebrew/bin/uv",      "args": [        "--directory",        "// todo python文件的文件夹路径,例如:/Users/yuguo/PycharmProjects/mcp-server-demo",        "run",        "// todo python文件名称,例如:python-mcp-test.py"      ],      "transportType": "stdio"    }  }}

HSF SSE:

{  "mcpServers": {    "// todo 你的HSF mcp server名称": {      "url": "// todo 从HSF控制台复制过来的url"    }  }}

最终效果:

CLINE自动调用“部门查询”的HSF服务查到了M3775是淘天。

参考文档

modelcontextprotocol.io/introductio…

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

MCP LLM AI应用 开放协议
相关文章