MCP学习

November 21, 2025

什么是MCP?

首先我们先明白,在没有MCP之前,我们想结合LLM和自己的知识进行回答,一般是通过 FunctionCall 或者代码层 if else,亦或者是插件、LangChain等。

在这里不是说这些解决方案不够好,而是相比 MCP 他们越来越定制化且不可拆分。这样一来、其他的 LLM客户端想调取你的能力就非常难。

所以 MCP 的出现是将能力进行模块化,给模型调用。

MCP 是 C/S 架构。可以理解为 Client 端会结合AI 应用决定和调取哪些 MCP Server。

此篇我们只开发 Server 服务。

MCP Server 和 Client 的通信可以是,本地Stdio,Http,也就是说 MCP Server可以是本地的、也可以是远程的。

通过 JSON 形式(JSON-RPC)进行数据传输约定。

从最简单的 Demo 开始。

让Cursor 列出我桌面的文件夹

import { readdir, stat } from 'fs/promises';
import { join } from 'path';
import { homedir } from 'os';
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

// 创建 MCP 服务器实例
// name 和 version 用于标识服务器
const server = new McpServer({
    name: "desktop_folders",
    version: "1.0.0"
});

/**
 * 注册工具:list_desktop_folders
 * 
 * server.tool() 方法用于注册一个可被 AI 调用的工具
 * 参数说明:
 *   - 第一个参数:工具名称(AI 通过这个名称调用工具)
 *   - 第二个参数:工具的参数定义(这里为空对象,表示不需要参数)
 *   - 第三个参数:工具的执行函数(异步函数,返回工具执行结果)
 */
server.tool(
    "list_desktop_folders",
    {}, // 工具参数定义(空对象表示无参数)
    async () => {
        try {
            // 获取桌面路径(跨平台兼容)
            const desktopPath = join(homedir(), 'Desktop');
            
            // 读取桌面目录下的所有文件和文件夹
            const items = await readdir(desktopPath);
            
            // 并行检查每个项目是否为文件夹(提高性能)
            const folderChecks = await Promise.all(
                items.map(async (item) => {
                    const itemPath = join(desktopPath, item);
                    const stats = await stat(itemPath);
                    return stats.isDirectory() ? item : null;
                })
            );
            
            // 过滤出文件夹名称(移除 null 值)
            const folders = folderChecks.filter(Boolean);
            
            // 格式化返回结果
            // MCP 工具必须返回特定格式:content 数组包含文本内容
            return {
                content: [{ 
                    type: "text", 
                    text: folders.length > 0
                        ? `桌面上的文件夹:\n${folders.join('\n')}\n\n共 ${folders.length} 个文件夹`
                        : '桌面上没有文件夹'
                }]
            };
        } catch (error) {
            // 错误处理:返回错误信息并标记为错误
            return {
                content: [{ 
                    type: "text", 
                    text: `错误:${error.message}`
                }],
                isError: true
            };
        }
    }
);

/**
 * 启动服务器
 * 
 * StdioServerTransport 使用标准输入输出进行通信
 * 这是 MCP 服务器最常见的通信方式
 */
const transport = new StdioServerTransport();
await server.connect(transport);

延展阅读

https://modelcontextprotocol.io/docs/develop/build-server